@mentra/bluetooth-sdk 0.1.4 → 0.1.6

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.
Files changed (72) hide show
  1. package/README.md +61 -42
  2. package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +20 -12
  3. package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +38 -12
  4. package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +2 -1
  5. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +45 -51
  6. package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +125 -0
  7. package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +187 -0
  8. package/android/src/main/java/com/mentra/bluetoothsdk/connection/ConnectionModels.kt +78 -0
  9. package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +60 -0
  10. package/android/src/main/java/com/mentra/bluetoothsdk/internal/MapParsing.kt +132 -0
  11. package/android/src/main/java/com/mentra/bluetoothsdk/requests/DisplayRequests.kt +39 -0
  12. package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +605 -0
  13. package/android/src/main/java/com/mentra/bluetoothsdk/status/RuntimeState.kt +199 -0
  14. package/android/src/main/java/com/mentra/bluetoothsdk/status/WifiHotspotStatus.kt +173 -0
  15. package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +348 -0
  16. package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +75 -0
  17. package/build/BluetoothSdk.types.d.ts +24 -7
  18. package/build/BluetoothSdk.types.d.ts.map +1 -1
  19. package/build/BluetoothSdk.types.js.map +1 -1
  20. package/build/_internal.d.ts +1 -1
  21. package/build/_internal.js +1 -1
  22. package/build/_internal.js.map +1 -1
  23. package/build/_private/BluetoothSdkModule.d.ts +5 -4
  24. package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
  25. package/build/_private/BluetoothSdkModule.js +4 -1
  26. package/build/_private/BluetoothSdkModule.js.map +1 -1
  27. package/build/index.d.ts +4 -3
  28. package/build/index.d.ts.map +1 -1
  29. package/build/index.js +81 -2
  30. package/build/index.js.map +1 -1
  31. package/build/react/index.d.ts +2 -2
  32. package/build/react/index.d.ts.map +1 -1
  33. package/build/react/index.js +1 -2
  34. package/build/react/index.js.map +1 -1
  35. package/build/react/useBluetoothStatus.js +1 -1
  36. package/build/react/useBluetoothStatus.js.map +1 -1
  37. package/build/react/useGlassesConnection.d.ts.map +1 -1
  38. package/build/react/useGlassesConnection.js +13 -0
  39. package/build/react/useGlassesConnection.js.map +1 -1
  40. package/build/react/useMentraBluetooth.d.ts +98 -0
  41. package/build/react/useMentraBluetooth.d.ts.map +1 -0
  42. package/build/react/useMentraBluetooth.js +156 -0
  43. package/build/react/useMentraBluetooth.js.map +1 -0
  44. package/ios/BluetoothSdkModule.swift +9 -9
  45. package/ios/Source/Audio/AudioModels.swift +159 -0
  46. package/ios/Source/Bridge.swift +42 -8
  47. package/ios/Source/Camera/CameraModels.swift +246 -0
  48. package/ios/Source/Connection/ScanSession.swift +27 -0
  49. package/ios/Source/DeviceManager.swift +0 -1
  50. package/ios/Source/DeviceStore.swift +2 -1
  51. package/ios/Source/Errors/BluetoothError.swift +19 -0
  52. package/ios/Source/Events/BluetoothEvents.swift +115 -0
  53. package/ios/Source/Internal/BluetoothAvailability.swift +58 -0
  54. package/ios/Source/Internal/ValueParsing.swift +90 -0
  55. package/ios/Source/MentraBluetoothSDK.swift +32 -2040
  56. package/ios/Source/Requests/DisplayRequests.swift +58 -0
  57. package/ios/Source/Status/DeviceStatus.swift +463 -0
  58. package/ios/Source/Status/RuntimeState.swift +350 -0
  59. package/ios/Source/Status/WifiHotspotStatus.swift +326 -0
  60. package/ios/Source/Streaming/StreamModels.swift +436 -0
  61. package/ios/Source/Types/DeviceModels.swift +134 -0
  62. package/ios/Source/sgcs/G2.swift +97 -36
  63. package/package.json +1 -1
  64. package/src/BluetoothSdk.types.ts +24 -7
  65. package/src/_internal.ts +1 -1
  66. package/src/_private/BluetoothSdkModule.ts +10 -5
  67. package/src/index.ts +93 -4
  68. package/src/react/index.ts +13 -11
  69. package/src/react/useBluetoothStatus.ts +1 -1
  70. package/src/react/useGlassesConnection.ts +15 -0
  71. package/src/react/useMentraBluetooth.ts +307 -0
  72. package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +0 -1725
@@ -1 +1 @@
1
- {"version":3,"file":"useBluetoothStatus.js","sourceRoot":"","sources":["../../src/react/useBluetoothStatus.ts"],"names":[],"mappings":"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","sourcesContent":["import {useEffect, useRef, useState} from \"react\"\n\nimport BluetoothSdk from \"../index\"\nimport {\n createDisconnectedGlassesStatus,\n isConnectedGlassesConnectionStatus,\n isReadyGlassesConnectionStatus,\n} from \"../BluetoothSdk.types\"\nimport type {\n BatteryStatusEvent,\n HotspotStatus,\n HotspotStatusChangeEvent,\n PublicBluetoothStatus,\n PublicGlassesStatus,\n WifiStatus,\n WifiStatusChangeEvent,\n} from \"../BluetoothSdk.types\"\n\nexport type UseBluetoothStatusOptions = {\n enabled?: boolean\n onError?: (error: unknown) => void\n}\n\nexport type BluetoothStatusHookResult = {\n bluetoothStatus: Partial<PublicBluetoothStatus>\n connected: boolean\n error: unknown | null\n glassesStatus: Partial<PublicGlassesStatus>\n loading: boolean\n ready: boolean\n refresh: () => Promise<void>\n}\n\nfunction wifiStatusFromEvent(event: WifiStatusChangeEvent): WifiStatus {\n switch (event.state) {\n case \"connected\":\n return {state: \"connected\", ssid: event.ssid, localIp: event.localIp}\n case \"disconnected\":\n return {state: \"disconnected\"}\n }\n}\n\nfunction hotspotStatusFromEvent(event: HotspotStatusChangeEvent): HotspotStatus {\n if (event.state === \"enabled\") {\n return {\n state: \"enabled\",\n ssid: event.ssid,\n password: event.password,\n localIp: event.localIp,\n }\n }\n return {state: event.state}\n}\n\nfunction mergeGlassesStatus(\n current: Partial<PublicGlassesStatus>,\n changed: Partial<PublicGlassesStatus>,\n): Partial<PublicGlassesStatus> {\n if (changed.connection?.state === \"disconnected\") {\n return {...createDisconnectedGlassesStatus(), ...changed}\n }\n return {...current, ...changed}\n}\n\nexport function useBluetoothStatus(options: UseBluetoothStatusOptions = {}): BluetoothStatusHookResult {\n const enabled = options.enabled ?? true\n const onErrorRef = useRef(options.onError)\n const [bluetoothStatus, setBluetoothStatus] = useState<Partial<PublicBluetoothStatus>>({})\n const [error, setError] = useState<unknown | null>(null)\n const [glassesStatus, setGlassesStatus] = useState<Partial<PublicGlassesStatus>>(() =>\n createDisconnectedGlassesStatus(),\n )\n const [loading, setLoading] = useState(enabled)\n\n useEffect(() => {\n onErrorRef.current = options.onError\n }, [options.onError])\n\n async function refresh() {\n setLoading(true)\n try {\n const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([\n BluetoothSdk.getGlassesStatus(),\n BluetoothSdk.getBluetoothStatus(),\n ])\n setGlassesStatus(nextGlassesStatus)\n setBluetoothStatus(nextBluetoothStatus)\n setError(null)\n } catch (nextError) {\n setError(nextError)\n onErrorRef.current?.(nextError)\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n if (!enabled) {\n setLoading(false)\n return undefined\n }\n\n let mounted = true\n\n const loadInitialStatus = async () => {\n setLoading(true)\n try {\n const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([\n BluetoothSdk.getGlassesStatus(),\n BluetoothSdk.getBluetoothStatus(),\n ])\n if (!mounted) {\n return\n }\n setGlassesStatus(nextGlassesStatus)\n setBluetoothStatus(nextBluetoothStatus)\n setError(null)\n } catch (nextError) {\n if (!mounted) {\n return\n }\n setError(nextError)\n onErrorRef.current?.(nextError)\n } finally {\n if (mounted) {\n setLoading(false)\n }\n }\n }\n\n void loadInitialStatus()\n\n const removeGlasses = BluetoothSdk.onGlassesStatus((changed) => {\n setGlassesStatus((current) => mergeGlassesStatus(current, changed))\n })\n const removeBluetooth = BluetoothSdk.onBluetoothStatus((changed) => {\n setBluetoothStatus((current) => ({...current, ...changed}))\n })\n const batterySubscription = BluetoothSdk.addListener(\"battery_status\", (event: BatteryStatusEvent) => {\n setGlassesStatus((current) => ({\n ...current,\n batteryLevel: event.level,\n charging: event.charging,\n }))\n })\n const wifiSubscription = BluetoothSdk.addListener(\"wifi_status_change\", (event) => {\n setGlassesStatus((current) => ({...current, wifi: wifiStatusFromEvent(event)}))\n })\n const hotspotSubscription = BluetoothSdk.addListener(\"hotspot_status_change\", (event) => {\n setGlassesStatus((current) => ({...current, hotspot: hotspotStatusFromEvent(event)}))\n })\n const hotspotErrorSubscription = BluetoothSdk.addListener(\"hotspot_error\", () => {\n setGlassesStatus((current) => ({...current, hotspot: {state: \"disabled\"}}))\n })\n\n return () => {\n mounted = false\n removeGlasses()\n removeBluetooth()\n batterySubscription.remove()\n wifiSubscription.remove()\n hotspotSubscription.remove()\n hotspotErrorSubscription.remove()\n }\n }, [enabled])\n\n const connection = glassesStatus.connection\n const connected = connection ? isConnectedGlassesConnectionStatus(connection) : false\n const ready = connection ? isReadyGlassesConnectionStatus(connection) : false\n\n return {\n bluetoothStatus,\n connected,\n error,\n glassesStatus,\n loading,\n ready,\n refresh,\n }\n}\n"]}
1
+ {"version":3,"file":"useBluetoothStatus.js","sourceRoot":"","sources":["../../src/react/useBluetoothStatus.ts"],"names":[],"mappings":"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","sourcesContent":["import {useEffect, useRef, useState} from \"react\"\n\nimport BluetoothSdk from \"../_private/BluetoothSdkModule\"\nimport {\n createDisconnectedGlassesStatus,\n isConnectedGlassesConnectionStatus,\n isReadyGlassesConnectionStatus,\n} from \"../BluetoothSdk.types\"\nimport type {\n BatteryStatusEvent,\n HotspotStatus,\n HotspotStatusChangeEvent,\n PublicBluetoothStatus,\n PublicGlassesStatus,\n WifiStatus,\n WifiStatusChangeEvent,\n} from \"../BluetoothSdk.types\"\n\nexport type UseBluetoothStatusOptions = {\n enabled?: boolean\n onError?: (error: unknown) => void\n}\n\nexport type BluetoothStatusHookResult = {\n bluetoothStatus: Partial<PublicBluetoothStatus>\n connected: boolean\n error: unknown | null\n glassesStatus: Partial<PublicGlassesStatus>\n loading: boolean\n ready: boolean\n refresh: () => Promise<void>\n}\n\nfunction wifiStatusFromEvent(event: WifiStatusChangeEvent): WifiStatus {\n switch (event.state) {\n case \"connected\":\n return {state: \"connected\", ssid: event.ssid, localIp: event.localIp}\n case \"disconnected\":\n return {state: \"disconnected\"}\n }\n}\n\nfunction hotspotStatusFromEvent(event: HotspotStatusChangeEvent): HotspotStatus {\n if (event.state === \"enabled\") {\n return {\n state: \"enabled\",\n ssid: event.ssid,\n password: event.password,\n localIp: event.localIp,\n }\n }\n return {state: event.state}\n}\n\nfunction mergeGlassesStatus(\n current: Partial<PublicGlassesStatus>,\n changed: Partial<PublicGlassesStatus>,\n): Partial<PublicGlassesStatus> {\n if (changed.connection?.state === \"disconnected\") {\n return {...createDisconnectedGlassesStatus(), ...changed}\n }\n return {...current, ...changed}\n}\n\nexport function useBluetoothStatus(options: UseBluetoothStatusOptions = {}): BluetoothStatusHookResult {\n const enabled = options.enabled ?? true\n const onErrorRef = useRef(options.onError)\n const [bluetoothStatus, setBluetoothStatus] = useState<Partial<PublicBluetoothStatus>>({})\n const [error, setError] = useState<unknown | null>(null)\n const [glassesStatus, setGlassesStatus] = useState<Partial<PublicGlassesStatus>>(() =>\n createDisconnectedGlassesStatus(),\n )\n const [loading, setLoading] = useState(enabled)\n\n useEffect(() => {\n onErrorRef.current = options.onError\n }, [options.onError])\n\n async function refresh() {\n setLoading(true)\n try {\n const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([\n BluetoothSdk.getGlassesStatus(),\n BluetoothSdk.getBluetoothStatus(),\n ])\n setGlassesStatus(nextGlassesStatus)\n setBluetoothStatus(nextBluetoothStatus)\n setError(null)\n } catch (nextError) {\n setError(nextError)\n onErrorRef.current?.(nextError)\n } finally {\n setLoading(false)\n }\n }\n\n useEffect(() => {\n if (!enabled) {\n setLoading(false)\n return undefined\n }\n\n let mounted = true\n\n const loadInitialStatus = async () => {\n setLoading(true)\n try {\n const [nextGlassesStatus, nextBluetoothStatus] = await Promise.all([\n BluetoothSdk.getGlassesStatus(),\n BluetoothSdk.getBluetoothStatus(),\n ])\n if (!mounted) {\n return\n }\n setGlassesStatus(nextGlassesStatus)\n setBluetoothStatus(nextBluetoothStatus)\n setError(null)\n } catch (nextError) {\n if (!mounted) {\n return\n }\n setError(nextError)\n onErrorRef.current?.(nextError)\n } finally {\n if (mounted) {\n setLoading(false)\n }\n }\n }\n\n void loadInitialStatus()\n\n const removeGlasses = BluetoothSdk.onGlassesStatus((changed) => {\n setGlassesStatus((current) => mergeGlassesStatus(current, changed))\n })\n const removeBluetooth = BluetoothSdk.onBluetoothStatus((changed) => {\n setBluetoothStatus((current) => ({...current, ...changed}))\n })\n const batterySubscription = BluetoothSdk.addListener(\"battery_status\", (event: BatteryStatusEvent) => {\n setGlassesStatus((current) => ({\n ...current,\n batteryLevel: event.level,\n charging: event.charging,\n }))\n })\n const wifiSubscription = BluetoothSdk.addListener(\"wifi_status_change\", (event) => {\n setGlassesStatus((current) => ({...current, wifi: wifiStatusFromEvent(event)}))\n })\n const hotspotSubscription = BluetoothSdk.addListener(\"hotspot_status_change\", (event) => {\n setGlassesStatus((current) => ({...current, hotspot: hotspotStatusFromEvent(event)}))\n })\n const hotspotErrorSubscription = BluetoothSdk.addListener(\"hotspot_error\", () => {\n setGlassesStatus((current) => ({...current, hotspot: {state: \"disabled\"}}))\n })\n\n return () => {\n mounted = false\n removeGlasses()\n removeBluetooth()\n batterySubscription.remove()\n wifiSubscription.remove()\n hotspotSubscription.remove()\n hotspotErrorSubscription.remove()\n }\n }, [enabled])\n\n const connection = glassesStatus.connection\n const connected = connection ? isConnectedGlassesConnectionStatus(connection) : false\n const ready = connection ? isReadyGlassesConnectionStatus(connection) : false\n\n return {\n bluetoothStatus,\n connected,\n error,\n glassesStatus,\n loading,\n ready,\n refresh,\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useGlassesConnection.d.ts","sourceRoot":"","sources":["../../src/react/useGlassesConnection.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAA;AAE9E,OAAO,EAAmB,KAAK,uBAAuB,EAAC,MAAM,oBAAoB,CAAA;AACjF,OAAO,EAAqB,KAAK,yBAAyB,EAAC,MAAM,sBAAsB,CAAA;AAEvF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAClC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/C,CAAA;AAED,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GACN,UAAU,GACV,YAAY,GACZ,eAAe,GACf,YAAY,CAAA;AAEhB,MAAM,MAAM,2BAA2B,GAAG;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG,yBAAyB,GAAG;IACpE,MAAM,EAAE,uBAAuB,CAAA;IAC/B,IAAI,EAAE,OAAO,CAAA;IACb,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,EAAE,uBAAuB,CAAA;IAC7B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3D,CAAA;AAED,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,2BAAgC,GACxC,2BAA2B,CAsJ7B"}
1
+ {"version":3,"file":"useGlassesConnection.d.ts","sourceRoot":"","sources":["../../src/react/useGlassesConnection.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAC,MAAM,uBAAuB,CAAA;AAE9E,OAAO,EAAmB,KAAK,uBAAuB,EAAC,MAAM,oBAAoB,CAAA;AACjF,OAAO,EAAqB,KAAK,yBAAyB,EAAC,MAAM,sBAAsB,CAAA;AAEvF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAClC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC/C,CAAA;AAED,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GACN,UAAU,GACV,YAAY,GACZ,eAAe,GACf,YAAY,CAAA;AAEhB,MAAM,MAAM,2BAA2B,GAAG;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,SAAS,CAAC,EAAE,WAAW,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG,yBAAyB,GAAG;IACpE,MAAM,EAAE,uBAAuB,CAAA;IAC/B,IAAI,EAAE,OAAO,CAAA;IACb,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,EAAE,uBAAuB,CAAA;IAC7B,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3D,CAAA;AAED,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,2BAAgC,GACxC,2BAA2B,CAqK7B"}
@@ -52,6 +52,19 @@ export function useGlassesConnection(options = {}) {
52
52
  mounted = false;
53
53
  };
54
54
  }, []);
55
+ useEffect(() => {
56
+ const subscription = BluetoothSdk.addListener("default_device_changed", (event) => {
57
+ const nextDefaultDevice = event.device ?? null;
58
+ setDefaultDeviceState(nextDefaultDevice);
59
+ void defaultDeviceStorageRef.current?.save(nextDefaultDevice).catch((nextError) => {
60
+ setOperationError(nextError);
61
+ onErrorRef.current?.(nextError);
62
+ });
63
+ });
64
+ return () => {
65
+ subscription.remove();
66
+ };
67
+ }, []);
55
68
  useEffect(() => {
56
69
  if (!options.autoConnectDefault || autoConnectAttemptedRef.current || status.connected || !defaultDevice) {
57
70
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"useGlassesConnection.js","sourceRoot":"","sources":["../../src/react/useGlassesConnection.ts"],"names":[],"mappings":"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","sourcesContent":["import {useEffect, useRef, useState} from \"react\"\n\nimport BluetoothSdk from \"../index\"\nimport type {ConnectOptions, Device, DeviceModel} from \"../BluetoothSdk.types\"\n\nimport {useBluetoothScan, type BluetoothScanHookResult} from \"./useBluetoothScan\"\nimport {useBluetoothStatus, type BluetoothStatusHookResult} from \"./useBluetoothStatus\"\n\nexport type DefaultDeviceStorage = {\n load: () => Promise<Device | null>\n save: (device: Device | null) => Promise<void>\n}\n\nexport type GlassesConnectionAction =\n | \"idle\"\n | \"scanning\"\n | \"connecting\"\n | \"disconnecting\"\n | \"forgetting\"\n\nexport type UseGlassesConnectionOptions = {\n autoConnectDefault?: boolean\n defaultDeviceStorage?: DefaultDeviceStorage\n onError?: (error: unknown) => void\n scanModel?: DeviceModel\n scanTimeoutMs?: number\n}\n\nexport type GlassesConnectionHookResult = BluetoothStatusHookResult & {\n action: GlassesConnectionAction\n busy: boolean\n clearDefaultDevice: () => Promise<void>\n connect: (device?: Device, options?: ConnectOptions) => Promise<void>\n connectDefault: (options?: ConnectOptions) => Promise<void>\n defaultDevice: Device | null\n disconnect: () => Promise<void>\n forget: () => Promise<void>\n scan: BluetoothScanHookResult\n setDefaultDevice: (device: Device | null) => Promise<void>\n}\n\nexport function useGlassesConnection(\n options: UseGlassesConnectionOptions = {},\n): GlassesConnectionHookResult {\n const status = useBluetoothStatus({onError: options.onError})\n const scan = useBluetoothScan({\n model: options.scanModel,\n onError: options.onError,\n timeoutMs: options.scanTimeoutMs,\n })\n const [action, setAction] = useState<GlassesConnectionAction>(\"idle\")\n const [defaultDevice, setDefaultDeviceState] = useState<Device | null>(null)\n const [operationError, setOperationError] = useState<unknown | null>(null)\n const autoConnectAttemptedRef = useRef(false)\n const defaultDeviceStorageRef = useRef(options.defaultDeviceStorage)\n const onErrorRef = useRef(options.onError)\n\n useEffect(() => {\n defaultDeviceStorageRef.current = options.defaultDeviceStorage\n onErrorRef.current = options.onError\n }, [options.defaultDeviceStorage, options.onError])\n\n useEffect(() => {\n let mounted = true\n\n const loadDefaultDevice = async () => {\n try {\n const [nativeDefaultDevice, storedDefaultDevice] = await Promise.all([\n BluetoothSdk.getDefaultDevice(),\n defaultDeviceStorageRef.current?.load() ?? Promise.resolve(null),\n ])\n if (!mounted) {\n return\n }\n const nextDefaultDevice = storedDefaultDevice ?? nativeDefaultDevice\n if (nextDefaultDevice) {\n await BluetoothSdk.setDefaultDevice(nextDefaultDevice)\n }\n if (mounted) {\n setDefaultDeviceState(nextDefaultDevice)\n setOperationError(null)\n }\n } catch (nextError) {\n if (!mounted) {\n return\n }\n setOperationError(nextError)\n onErrorRef.current?.(nextError)\n }\n }\n\n void loadDefaultDevice()\n\n return () => {\n mounted = false\n }\n }, [])\n\n useEffect(() => {\n if (!options.autoConnectDefault || autoConnectAttemptedRef.current || status.connected || !defaultDevice) {\n return\n }\n\n autoConnectAttemptedRef.current = true\n void connectDefault().catch(() => undefined)\n }, [defaultDevice, options.autoConnectDefault, status.connected])\n\n async function runConnectionAction<T>(\n nextAction: Exclude<GlassesConnectionAction, \"idle\" | \"scanning\">,\n operation: () => Promise<T>,\n ): Promise<T> {\n setAction(nextAction)\n setOperationError(null)\n try {\n const result = await operation()\n setOperationError(null)\n return result\n } catch (nextError) {\n setOperationError(nextError)\n onErrorRef.current?.(nextError)\n throw nextError\n } finally {\n setAction(\"idle\")\n }\n }\n\n async function setDefaultDevice(device: Device | null) {\n await runConnectionAction(\"connecting\", async () => {\n await BluetoothSdk.setDefaultDevice(device)\n await defaultDeviceStorageRef.current?.save(device)\n setDefaultDeviceState(device)\n })\n }\n\n async function clearDefaultDevice() {\n await runConnectionAction(\"forgetting\", async () => {\n await BluetoothSdk.clearDefaultDevice()\n await defaultDeviceStorageRef.current?.save(null)\n setDefaultDeviceState(null)\n scan.selectDevice(null)\n })\n }\n\n async function connect(device?: Device, connectOptions?: ConnectOptions) {\n await runConnectionAction(\"connecting\", async () => {\n const targetDevice = device ?? scan.selectedDevice\n if (targetDevice) {\n await BluetoothSdk.connect(targetDevice, connectOptions)\n if (connectOptions?.saveAsDefault !== false) {\n await defaultDeviceStorageRef.current?.save(targetDevice)\n setDefaultDeviceState(targetDevice)\n }\n return\n }\n await BluetoothSdk.connectDefault(connectOptions)\n })\n }\n\n async function connectDefault(connectOptions?: ConnectOptions) {\n await runConnectionAction(\"connecting\", async () => {\n await BluetoothSdk.connectDefault(connectOptions)\n })\n }\n\n async function disconnect() {\n await runConnectionAction(\"disconnecting\", async () => {\n await BluetoothSdk.disconnect()\n })\n }\n\n async function forget() {\n await runConnectionAction(\"forgetting\", async () => {\n await BluetoothSdk.forget()\n scan.clearResults()\n })\n }\n\n const busy = action !== \"idle\" || scan.scanning || status.loading\n\n return {\n ...status,\n action: scan.scanning ? \"scanning\" : action,\n busy,\n clearDefaultDevice,\n connect,\n connectDefault,\n defaultDevice,\n disconnect,\n error: operationError ?? scan.error ?? status.error,\n forget,\n scan,\n setDefaultDevice,\n }\n}\n"]}
1
+ {"version":3,"file":"useGlassesConnection.js","sourceRoot":"","sources":["../../src/react/useGlassesConnection.ts"],"names":[],"mappings":"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","sourcesContent":["import {useEffect, useRef, useState} from \"react\"\n\nimport BluetoothSdk from \"../index\"\nimport type {ConnectOptions, Device, DeviceModel} from \"../BluetoothSdk.types\"\n\nimport {useBluetoothScan, type BluetoothScanHookResult} from \"./useBluetoothScan\"\nimport {useBluetoothStatus, type BluetoothStatusHookResult} from \"./useBluetoothStatus\"\n\nexport type DefaultDeviceStorage = {\n load: () => Promise<Device | null>\n save: (device: Device | null) => Promise<void>\n}\n\nexport type GlassesConnectionAction =\n | \"idle\"\n | \"scanning\"\n | \"connecting\"\n | \"disconnecting\"\n | \"forgetting\"\n\nexport type UseGlassesConnectionOptions = {\n autoConnectDefault?: boolean\n defaultDeviceStorage?: DefaultDeviceStorage\n onError?: (error: unknown) => void\n scanModel?: DeviceModel\n scanTimeoutMs?: number\n}\n\nexport type GlassesConnectionHookResult = BluetoothStatusHookResult & {\n action: GlassesConnectionAction\n busy: boolean\n clearDefaultDevice: () => Promise<void>\n connect: (device?: Device, options?: ConnectOptions) => Promise<void>\n connectDefault: (options?: ConnectOptions) => Promise<void>\n defaultDevice: Device | null\n disconnect: () => Promise<void>\n forget: () => Promise<void>\n scan: BluetoothScanHookResult\n setDefaultDevice: (device: Device | null) => Promise<void>\n}\n\nexport function useGlassesConnection(\n options: UseGlassesConnectionOptions = {},\n): GlassesConnectionHookResult {\n const status = useBluetoothStatus({onError: options.onError})\n const scan = useBluetoothScan({\n model: options.scanModel,\n onError: options.onError,\n timeoutMs: options.scanTimeoutMs,\n })\n const [action, setAction] = useState<GlassesConnectionAction>(\"idle\")\n const [defaultDevice, setDefaultDeviceState] = useState<Device | null>(null)\n const [operationError, setOperationError] = useState<unknown | null>(null)\n const autoConnectAttemptedRef = useRef(false)\n const defaultDeviceStorageRef = useRef(options.defaultDeviceStorage)\n const onErrorRef = useRef(options.onError)\n\n useEffect(() => {\n defaultDeviceStorageRef.current = options.defaultDeviceStorage\n onErrorRef.current = options.onError\n }, [options.defaultDeviceStorage, options.onError])\n\n useEffect(() => {\n let mounted = true\n\n const loadDefaultDevice = async () => {\n try {\n const [nativeDefaultDevice, storedDefaultDevice] = await Promise.all([\n BluetoothSdk.getDefaultDevice(),\n defaultDeviceStorageRef.current?.load() ?? Promise.resolve(null),\n ])\n if (!mounted) {\n return\n }\n const nextDefaultDevice = storedDefaultDevice ?? nativeDefaultDevice\n if (nextDefaultDevice) {\n await BluetoothSdk.setDefaultDevice(nextDefaultDevice)\n }\n if (mounted) {\n setDefaultDeviceState(nextDefaultDevice)\n setOperationError(null)\n }\n } catch (nextError) {\n if (!mounted) {\n return\n }\n setOperationError(nextError)\n onErrorRef.current?.(nextError)\n }\n }\n\n void loadDefaultDevice()\n\n return () => {\n mounted = false\n }\n }, [])\n\n useEffect(() => {\n const subscription = BluetoothSdk.addListener(\"default_device_changed\", (event) => {\n const nextDefaultDevice = event.device ?? null\n setDefaultDeviceState(nextDefaultDevice)\n void defaultDeviceStorageRef.current?.save(nextDefaultDevice).catch((nextError) => {\n setOperationError(nextError)\n onErrorRef.current?.(nextError)\n })\n })\n\n return () => {\n subscription.remove()\n }\n }, [])\n\n useEffect(() => {\n if (!options.autoConnectDefault || autoConnectAttemptedRef.current || status.connected || !defaultDevice) {\n return\n }\n\n autoConnectAttemptedRef.current = true\n void connectDefault().catch(() => undefined)\n }, [defaultDevice, options.autoConnectDefault, status.connected])\n\n async function runConnectionAction<T>(\n nextAction: Exclude<GlassesConnectionAction, \"idle\" | \"scanning\">,\n operation: () => Promise<T>,\n ): Promise<T> {\n setAction(nextAction)\n setOperationError(null)\n try {\n const result = await operation()\n setOperationError(null)\n return result\n } catch (nextError) {\n setOperationError(nextError)\n onErrorRef.current?.(nextError)\n throw nextError\n } finally {\n setAction(\"idle\")\n }\n }\n\n async function setDefaultDevice(device: Device | null) {\n await runConnectionAction(\"connecting\", async () => {\n await BluetoothSdk.setDefaultDevice(device)\n await defaultDeviceStorageRef.current?.save(device)\n setDefaultDeviceState(device)\n })\n }\n\n async function clearDefaultDevice() {\n await runConnectionAction(\"forgetting\", async () => {\n await BluetoothSdk.clearDefaultDevice()\n await defaultDeviceStorageRef.current?.save(null)\n setDefaultDeviceState(null)\n scan.selectDevice(null)\n })\n }\n\n async function connect(device?: Device, connectOptions?: ConnectOptions) {\n await runConnectionAction(\"connecting\", async () => {\n const targetDevice = device ?? scan.selectedDevice\n if (targetDevice) {\n await BluetoothSdk.connect(targetDevice, connectOptions)\n if (connectOptions?.saveAsDefault !== false) {\n await defaultDeviceStorageRef.current?.save(targetDevice)\n setDefaultDeviceState(targetDevice)\n }\n return\n }\n await BluetoothSdk.connectDefault(connectOptions)\n })\n }\n\n async function connectDefault(connectOptions?: ConnectOptions) {\n await runConnectionAction(\"connecting\", async () => {\n await BluetoothSdk.connectDefault(connectOptions)\n })\n }\n\n async function disconnect() {\n await runConnectionAction(\"disconnecting\", async () => {\n await BluetoothSdk.disconnect()\n })\n }\n\n async function forget() {\n await runConnectionAction(\"forgetting\", async () => {\n await BluetoothSdk.forget()\n scan.clearResults()\n })\n }\n\n const busy = action !== \"idle\" || scan.scanning || status.loading\n\n return {\n ...status,\n action: scan.scanning ? \"scanning\" : action,\n busy,\n clearDefaultDevice,\n connect,\n connectDefault,\n defaultDevice,\n disconnect,\n error: operationError ?? scan.error ?? status.error,\n forget,\n scan,\n setDefaultDevice,\n }\n}\n"]}
@@ -0,0 +1,98 @@
1
+ import type { ConnectOptions, Device, DeviceModel, GalleryMode, GlassesConnectionStatus, HotspotStatus, MicMode, WifiSearchResult, WifiStatus } from "../BluetoothSdk.types";
2
+ import { type DefaultDeviceStorage } from "./useGlassesConnection";
3
+ export type BatteryState = {
4
+ charging: boolean;
5
+ level: number | null;
6
+ };
7
+ export type ConnectedGlassesInfo = {
8
+ appVersion?: string;
9
+ bluetoothName?: string;
10
+ buildNumber?: string;
11
+ color?: string;
12
+ deviceModel?: string;
13
+ firmwareVersion?: string;
14
+ serialNumber?: string;
15
+ style?: string;
16
+ };
17
+ export type FirmwareInfo = {
18
+ appVersion?: string;
19
+ buildNumber?: string;
20
+ source: "app" | "bes" | "device" | "firmware" | "left" | "mtk" | "right" | "unknown";
21
+ version: string | null;
22
+ };
23
+ export type SignalState = {
24
+ strengthDbm: number | null;
25
+ updatedAt: number | null;
26
+ };
27
+ export type GlassesRuntimeState = {
28
+ connected: false;
29
+ connection: Exclude<GlassesConnectionStatus, {
30
+ state: "connected";
31
+ }>;
32
+ ready: false;
33
+ } | {
34
+ battery: BatteryState;
35
+ connected: true;
36
+ connection: Extract<GlassesConnectionStatus, {
37
+ state: "connected";
38
+ }>;
39
+ device: ConnectedGlassesInfo;
40
+ firmware: FirmwareInfo;
41
+ hotspot: HotspotStatus;
42
+ ready: boolean;
43
+ signal: SignalState;
44
+ wifi: WifiStatus;
45
+ };
46
+ export type GalleryModeState = {
47
+ applying: boolean;
48
+ desired: GalleryMode;
49
+ error: unknown | null;
50
+ };
51
+ export type PhoneSdkRuntimeState = {
52
+ currentMic: MicMode | null;
53
+ defaultDevice: Device | null;
54
+ galleryMode: GalleryModeState;
55
+ lastLog: string[];
56
+ micRanking: MicMode[];
57
+ otherBluetoothConnected: boolean;
58
+ searching: boolean;
59
+ searchingController: boolean;
60
+ systemMicUnavailable: boolean;
61
+ wifiScanResults: WifiSearchResult[];
62
+ };
63
+ export type ScanController = {
64
+ active: boolean;
65
+ clear: () => void;
66
+ devices: Device[];
67
+ error: unknown | null;
68
+ model: DeviceModel;
69
+ selectedDevice: Device | null;
70
+ selectDevice: (device: Device | null) => void;
71
+ setModel: (model: DeviceModel) => void;
72
+ start: (model?: DeviceModel) => Promise<Device[]>;
73
+ stop: () => Promise<void>;
74
+ };
75
+ export type UseMentraBluetoothOptions = {
76
+ autoConnectDefault?: boolean;
77
+ defaultDeviceStorage?: DefaultDeviceStorage;
78
+ defaultModel?: DeviceModel;
79
+ onError?: (error: unknown) => void;
80
+ scanTimeoutMs?: number;
81
+ };
82
+ export type MentraBluetoothSession = {
83
+ busy: boolean;
84
+ clearDefaultDevice: () => Promise<void>;
85
+ connect: (device?: Device, options?: ConnectOptions) => Promise<void>;
86
+ connectDefault: (options?: ConnectOptions) => Promise<void>;
87
+ defaultDevice: Device | null;
88
+ disconnect: () => Promise<void>;
89
+ error: unknown | null;
90
+ glasses: GlassesRuntimeState;
91
+ refresh: () => Promise<void>;
92
+ scan: ScanController;
93
+ sdk: PhoneSdkRuntimeState;
94
+ setDefaultDevice: (device: Device | null) => Promise<void>;
95
+ setGalleryMode: (mode: GalleryMode) => Promise<void>;
96
+ };
97
+ export declare function useMentraBluetooth(options?: UseMentraBluetoothOptions): MentraBluetoothSession;
98
+ //# sourceMappingURL=useMentraBluetooth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMentraBluetooth.d.ts","sourceRoot":"","sources":["../../src/react/useMentraBluetooth.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,cAAc,EACd,MAAM,EACN,WAAW,EACX,WAAW,EACX,uBAAuB,EACvB,aAAa,EAGb,OAAO,EACP,gBAAgB,EAChB,UAAU,EACX,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAEL,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAA;AAE/B,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,OAAO,CAAA;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,EACF,KAAK,GACL,KAAK,GACL,QAAQ,GACR,UAAU,GACV,MAAM,GACN,KAAK,GACL,OAAO,GACP,SAAS,CAAA;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAC3B;IACE,SAAS,EAAE,KAAK,CAAA;IAChB,UAAU,EAAE,OAAO,CAAC,uBAAuB,EAAE;QAAC,KAAK,EAAE,WAAW,CAAA;KAAC,CAAC,CAAA;IAClE,KAAK,EAAE,KAAK,CAAA;CACb,GACD;IACE,OAAO,EAAE,YAAY,CAAA;IACrB,SAAS,EAAE,IAAI,CAAA;IACf,UAAU,EAAE,OAAO,CAAC,uBAAuB,EAAE;QAAC,KAAK,EAAE,WAAW,CAAA;KAAC,CAAC,CAAA;IAClE,MAAM,EAAE,oBAAoB,CAAA;IAC5B,QAAQ,EAAE,YAAY,CAAA;IACtB,OAAO,EAAE,aAAa,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,WAAW,CAAA;IACnB,IAAI,EAAE,UAAU,CAAA;CACjB,CAAA;AAEL,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,WAAW,CAAA;IACpB,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,OAAO,GAAG,IAAI,CAAA;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,WAAW,EAAE,gBAAgB,CAAA;IAC7B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,UAAU,EAAE,OAAO,EAAE,CAAA;IACrB,uBAAuB,EAAE,OAAO,CAAA;IAChC,SAAS,EAAE,OAAO,CAAA;IAClB,mBAAmB,EAAE,OAAO,CAAA;IAC5B,oBAAoB,EAAE,OAAO,CAAA;IAC7B,eAAe,EAAE,gBAAgB,EAAE,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,OAAO,CAAA;IACf,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IACrB,KAAK,EAAE,WAAW,CAAA;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IAC7C,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAA;IACtC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACjD,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,YAAY,CAAC,EAAE,WAAW,CAAA;IAC1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IAClC,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,OAAO,CAAA;IACb,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,cAAc,EAAE,CAAC,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/B,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;IACrB,OAAO,EAAE,mBAAmB,CAAA;IAC5B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5B,IAAI,EAAE,cAAc,CAAA;IACpB,GAAG,EAAE,oBAAoB,CAAA;IACzB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1D,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACrD,CAAA;AA2HD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,sBAAsB,CA8ClG"}
@@ -0,0 +1,156 @@
1
+ import { useState } from "react";
2
+ import BluetoothSdk from "../index";
3
+ import { DeviceModels, createDisconnectedGlassesStatus, isConnectedGlassesConnectionStatus, isReadyGlassesConnectionStatus, } from "../BluetoothSdk.types";
4
+ import { useGlassesConnection, } from "./useGlassesConnection";
5
+ function stringValue(value) {
6
+ return typeof value === "string" && value.length > 0 ? value : undefined;
7
+ }
8
+ function numberValue(value) {
9
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
10
+ }
11
+ function firmwareInfo(status) {
12
+ const firmwareSources = [
13
+ ["firmwareVersion", "firmware"],
14
+ ["deviceFirmwareVersion", "device"],
15
+ ["rightFirmwareVersion", "right"],
16
+ ["leftFirmwareVersion", "left"],
17
+ ["besFirmwareVersion", "bes"],
18
+ ["mtkFirmwareVersion", "mtk"],
19
+ ["appVersion", "app"],
20
+ ];
21
+ for (const [key, source] of firmwareSources) {
22
+ const value = stringValue(status[key]);
23
+ if (value) {
24
+ return {
25
+ appVersion: stringValue(status.appVersion),
26
+ buildNumber: stringValue(status.buildNumber),
27
+ source,
28
+ version: value,
29
+ };
30
+ }
31
+ }
32
+ return {
33
+ appVersion: stringValue(status.appVersion),
34
+ buildNumber: stringValue(status.buildNumber),
35
+ source: "unknown",
36
+ version: null,
37
+ };
38
+ }
39
+ function batteryState(status) {
40
+ const level = typeof status.batteryLevel === "number" && status.batteryLevel >= 0 ? status.batteryLevel : null;
41
+ return {
42
+ charging: status.charging ?? false,
43
+ level,
44
+ };
45
+ }
46
+ function connectedGlassesInfo(status) {
47
+ return {
48
+ appVersion: stringValue(status.appVersion),
49
+ bluetoothName: stringValue(status.bluetoothName),
50
+ buildNumber: stringValue(status.buildNumber),
51
+ color: stringValue(status.color),
52
+ deviceModel: stringValue(status.deviceModel),
53
+ firmwareVersion: stringValue(status.firmwareVersion),
54
+ serialNumber: stringValue(status.serialNumber),
55
+ style: stringValue(status.style),
56
+ };
57
+ }
58
+ function runtimeGlassesState(status) {
59
+ const connection = status.connection ?? createDisconnectedGlassesStatus().connection ?? { state: "disconnected" };
60
+ if (!isConnectedGlassesConnectionStatus(connection)) {
61
+ return {
62
+ connected: false,
63
+ connection,
64
+ ready: false,
65
+ };
66
+ }
67
+ return {
68
+ battery: batteryState(status),
69
+ connected: true,
70
+ connection,
71
+ device: connectedGlassesInfo(status),
72
+ firmware: firmwareInfo(status),
73
+ hotspot: status.hotspot ?? { state: "disabled" },
74
+ ready: isReadyGlassesConnectionStatus(connection),
75
+ signal: {
76
+ strengthDbm: numberValue(status.signalStrength),
77
+ updatedAt: numberValue(status.signalStrengthUpdatedAt),
78
+ },
79
+ wifi: status.wifi ?? { state: "disconnected" },
80
+ };
81
+ }
82
+ function phoneSdkState(status, defaultDevice, galleryMode) {
83
+ return {
84
+ currentMic: status.currentMic || null,
85
+ defaultDevice,
86
+ galleryMode,
87
+ lastLog: status.lastLog ?? [],
88
+ micRanking: status.micRanking ?? [],
89
+ otherBluetoothConnected: status.otherBtConnected ?? false,
90
+ searching: status.searching ?? false,
91
+ searchingController: status.searchingController ?? false,
92
+ systemMicUnavailable: status.systemMicUnavailable ?? false,
93
+ wifiScanResults: status.wifiScanResults ?? [],
94
+ };
95
+ }
96
+ function scanController(connection) {
97
+ return {
98
+ active: connection.scan.scanning,
99
+ clear: connection.scan.clearResults,
100
+ devices: connection.scan.devices,
101
+ error: connection.scan.error,
102
+ model: connection.scan.model,
103
+ selectedDevice: connection.scan.selectedDevice,
104
+ selectDevice: connection.scan.selectDevice,
105
+ setModel: connection.scan.setModel,
106
+ start: connection.scan.startScan,
107
+ stop: connection.scan.stopScan,
108
+ };
109
+ }
110
+ export function useMentraBluetooth(options = {}) {
111
+ const connection = useGlassesConnection({
112
+ autoConnectDefault: options.autoConnectDefault,
113
+ defaultDeviceStorage: options.defaultDeviceStorage,
114
+ onError: options.onError,
115
+ scanModel: options.defaultModel ?? DeviceModels.MentraLive,
116
+ scanTimeoutMs: options.scanTimeoutMs,
117
+ });
118
+ const [galleryModeApplying, setGalleryModeApplying] = useState(false);
119
+ const [galleryModeError, setGalleryModeError] = useState(null);
120
+ async function setGalleryMode(mode) {
121
+ setGalleryModeApplying(true);
122
+ setGalleryModeError(null);
123
+ try {
124
+ await BluetoothSdk.setGalleryMode(mode);
125
+ }
126
+ catch (error) {
127
+ setGalleryModeError(error);
128
+ options.onError?.(error);
129
+ throw error;
130
+ }
131
+ finally {
132
+ setGalleryModeApplying(false);
133
+ }
134
+ }
135
+ const galleryMode = {
136
+ applying: galleryModeApplying,
137
+ desired: connection.bluetoothStatus.galleryModeAuto === false ? "manual" : "auto",
138
+ error: galleryModeError,
139
+ };
140
+ return {
141
+ busy: connection.busy || galleryModeApplying,
142
+ clearDefaultDevice: connection.clearDefaultDevice,
143
+ connect: connection.connect,
144
+ connectDefault: connection.connectDefault,
145
+ defaultDevice: connection.defaultDevice,
146
+ disconnect: connection.disconnect,
147
+ error: galleryModeError ?? connection.error,
148
+ glasses: runtimeGlassesState(connection.glassesStatus),
149
+ refresh: connection.refresh,
150
+ scan: scanController(connection),
151
+ sdk: phoneSdkState(connection.bluetoothStatus, connection.defaultDevice, galleryMode),
152
+ setDefaultDevice: connection.setDefaultDevice,
153
+ setGalleryMode,
154
+ };
155
+ }
156
+ //# sourceMappingURL=useMentraBluetooth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMentraBluetooth.js","sourceRoot":"","sources":["../../src/react/useMentraBluetooth.ts"],"names":[],"mappings":"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","sourcesContent":["import {useState} from \"react\"\n\nimport BluetoothSdk from \"../index\"\nimport {\n DeviceModels,\n createDisconnectedGlassesStatus,\n isConnectedGlassesConnectionStatus,\n isReadyGlassesConnectionStatus,\n} from \"../BluetoothSdk.types\"\nimport type {\n ConnectOptions,\n Device,\n DeviceModel,\n GalleryMode,\n GlassesConnectionStatus,\n HotspotStatus,\n PublicBluetoothStatus,\n PublicGlassesStatus,\n MicMode,\n WifiSearchResult,\n WifiStatus,\n} from \"../BluetoothSdk.types\"\n\nimport {\n useGlassesConnection,\n type DefaultDeviceStorage,\n type GlassesConnectionHookResult,\n} from \"./useGlassesConnection\"\n\nexport type BatteryState = {\n charging: boolean\n level: number | null\n}\n\nexport type ConnectedGlassesInfo = {\n appVersion?: string\n bluetoothName?: string\n buildNumber?: string\n color?: string\n deviceModel?: string\n firmwareVersion?: string\n serialNumber?: string\n style?: string\n}\n\nexport type FirmwareInfo = {\n appVersion?: string\n buildNumber?: string\n source:\n | \"app\"\n | \"bes\"\n | \"device\"\n | \"firmware\"\n | \"left\"\n | \"mtk\"\n | \"right\"\n | \"unknown\"\n version: string | null\n}\n\nexport type SignalState = {\n strengthDbm: number | null\n updatedAt: number | null\n}\n\nexport type GlassesRuntimeState =\n | {\n connected: false\n connection: Exclude<GlassesConnectionStatus, {state: \"connected\"}>\n ready: false\n }\n | {\n battery: BatteryState\n connected: true\n connection: Extract<GlassesConnectionStatus, {state: \"connected\"}>\n device: ConnectedGlassesInfo\n firmware: FirmwareInfo\n hotspot: HotspotStatus\n ready: boolean\n signal: SignalState\n wifi: WifiStatus\n }\n\nexport type GalleryModeState = {\n applying: boolean\n desired: GalleryMode\n error: unknown | null\n}\n\nexport type PhoneSdkRuntimeState = {\n currentMic: MicMode | null\n defaultDevice: Device | null\n galleryMode: GalleryModeState\n lastLog: string[]\n micRanking: MicMode[]\n otherBluetoothConnected: boolean\n searching: boolean\n searchingController: boolean\n systemMicUnavailable: boolean\n wifiScanResults: WifiSearchResult[]\n}\n\nexport type ScanController = {\n active: boolean\n clear: () => void\n devices: Device[]\n error: unknown | null\n model: DeviceModel\n selectedDevice: Device | null\n selectDevice: (device: Device | null) => void\n setModel: (model: DeviceModel) => void\n start: (model?: DeviceModel) => Promise<Device[]>\n stop: () => Promise<void>\n}\n\nexport type UseMentraBluetoothOptions = {\n autoConnectDefault?: boolean\n defaultDeviceStorage?: DefaultDeviceStorage\n defaultModel?: DeviceModel\n onError?: (error: unknown) => void\n scanTimeoutMs?: number\n}\n\nexport type MentraBluetoothSession = {\n busy: boolean\n clearDefaultDevice: () => Promise<void>\n connect: (device?: Device, options?: ConnectOptions) => Promise<void>\n connectDefault: (options?: ConnectOptions) => Promise<void>\n defaultDevice: Device | null\n disconnect: () => Promise<void>\n error: unknown | null\n glasses: GlassesRuntimeState\n refresh: () => Promise<void>\n scan: ScanController\n sdk: PhoneSdkRuntimeState\n setDefaultDevice: (device: Device | null) => Promise<void>\n setGalleryMode: (mode: GalleryMode) => Promise<void>\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined\n}\n\nfunction numberValue(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null\n}\n\nfunction firmwareInfo(status: Partial<PublicGlassesStatus>): FirmwareInfo {\n const firmwareSources = [\n [\"firmwareVersion\", \"firmware\"],\n [\"deviceFirmwareVersion\", \"device\"],\n [\"rightFirmwareVersion\", \"right\"],\n [\"leftFirmwareVersion\", \"left\"],\n [\"besFirmwareVersion\", \"bes\"],\n [\"mtkFirmwareVersion\", \"mtk\"],\n [\"appVersion\", \"app\"],\n ] as const\n\n for (const [key, source] of firmwareSources) {\n const value = stringValue((status as Record<string, unknown>)[key])\n if (value) {\n return {\n appVersion: stringValue(status.appVersion),\n buildNumber: stringValue(status.buildNumber),\n source,\n version: value,\n }\n }\n }\n\n return {\n appVersion: stringValue(status.appVersion),\n buildNumber: stringValue(status.buildNumber),\n source: \"unknown\",\n version: null,\n }\n}\n\nfunction batteryState(status: Partial<PublicGlassesStatus>): BatteryState {\n const level = typeof status.batteryLevel === \"number\" && status.batteryLevel >= 0 ? status.batteryLevel : null\n return {\n charging: status.charging ?? false,\n level,\n }\n}\n\nfunction connectedGlassesInfo(status: Partial<PublicGlassesStatus>): ConnectedGlassesInfo {\n return {\n appVersion: stringValue(status.appVersion),\n bluetoothName: stringValue(status.bluetoothName),\n buildNumber: stringValue(status.buildNumber),\n color: stringValue(status.color),\n deviceModel: stringValue(status.deviceModel),\n firmwareVersion: stringValue(status.firmwareVersion),\n serialNumber: stringValue(status.serialNumber),\n style: stringValue(status.style),\n }\n}\n\nfunction runtimeGlassesState(status: Partial<PublicGlassesStatus>): GlassesRuntimeState {\n const connection = status.connection ?? createDisconnectedGlassesStatus().connection ?? {state: \"disconnected\"}\n\n if (!isConnectedGlassesConnectionStatus(connection)) {\n return {\n connected: false,\n connection,\n ready: false,\n }\n }\n\n return {\n battery: batteryState(status),\n connected: true,\n connection,\n device: connectedGlassesInfo(status),\n firmware: firmwareInfo(status),\n hotspot: status.hotspot ?? {state: \"disabled\"},\n ready: isReadyGlassesConnectionStatus(connection),\n signal: {\n strengthDbm: numberValue((status as Record<string, unknown>).signalStrength),\n updatedAt: numberValue((status as Record<string, unknown>).signalStrengthUpdatedAt),\n },\n wifi: status.wifi ?? {state: \"disconnected\"},\n }\n}\n\nfunction phoneSdkState(\n status: Partial<PublicBluetoothStatus>,\n defaultDevice: Device | null,\n galleryMode: GalleryModeState,\n): PhoneSdkRuntimeState {\n return {\n currentMic: status.currentMic || null,\n defaultDevice,\n galleryMode,\n lastLog: status.lastLog ?? [],\n micRanking: status.micRanking ?? [],\n otherBluetoothConnected: status.otherBtConnected ?? false,\n searching: status.searching ?? false,\n searchingController: status.searchingController ?? false,\n systemMicUnavailable: status.systemMicUnavailable ?? false,\n wifiScanResults: status.wifiScanResults ?? [],\n }\n}\n\nfunction scanController(connection: GlassesConnectionHookResult): ScanController {\n return {\n active: connection.scan.scanning,\n clear: connection.scan.clearResults,\n devices: connection.scan.devices,\n error: connection.scan.error,\n model: connection.scan.model,\n selectedDevice: connection.scan.selectedDevice,\n selectDevice: connection.scan.selectDevice,\n setModel: connection.scan.setModel,\n start: connection.scan.startScan,\n stop: connection.scan.stopScan,\n }\n}\n\nexport function useMentraBluetooth(options: UseMentraBluetoothOptions = {}): MentraBluetoothSession {\n const connection = useGlassesConnection({\n autoConnectDefault: options.autoConnectDefault,\n defaultDeviceStorage: options.defaultDeviceStorage,\n onError: options.onError,\n scanModel: options.defaultModel ?? DeviceModels.MentraLive,\n scanTimeoutMs: options.scanTimeoutMs,\n })\n const [galleryModeApplying, setGalleryModeApplying] = useState(false)\n const [galleryModeError, setGalleryModeError] = useState<unknown | null>(null)\n\n async function setGalleryMode(mode: GalleryMode) {\n setGalleryModeApplying(true)\n setGalleryModeError(null)\n try {\n await BluetoothSdk.setGalleryMode(mode)\n } catch (error) {\n setGalleryModeError(error)\n options.onError?.(error)\n throw error\n } finally {\n setGalleryModeApplying(false)\n }\n }\n\n const galleryMode: GalleryModeState = {\n applying: galleryModeApplying,\n desired: connection.bluetoothStatus.galleryModeAuto === false ? \"manual\" : \"auto\",\n error: galleryModeError,\n }\n\n return {\n busy: connection.busy || galleryModeApplying,\n clearDefaultDevice: connection.clearDefaultDevice,\n connect: connection.connect,\n connectDefault: connection.connectDefault,\n defaultDevice: connection.defaultDevice,\n disconnect: connection.disconnect,\n error: galleryModeError ?? connection.error,\n glasses: runtimeGlassesState(connection.glassesStatus),\n refresh: connection.refresh,\n scan: scanController(connection),\n sdk: phoneSdkState(connection.bluetoothStatus, connection.defaultDevice, galleryMode),\n setDefaultDevice: connection.setDefaultDevice,\n setGalleryMode,\n }\n}\n"]}
@@ -457,7 +457,7 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
457
457
  self.bluetoothSdk().setMicState(
458
458
  enabled: enabled,
459
459
  useGlassesMic: useGlassesMic ?? true,
460
- bypassVad: bypassVad ?? false,
460
+ bypassVad: bypassVad ?? true,
461
461
  sendTranscript: sendTranscript ?? false,
462
462
  sendLc3Data: sendLc3Data ?? false
463
463
  )
@@ -527,13 +527,13 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
527
527
  }
528
528
 
529
529
  @MainActor
530
- public func mentraBluetoothSDK(_: MentraBluetoothSDK, didUpdateGlassesStatus status: GlassesStatusUpdate) {
531
- sendEvent("glasses_status", status.dictionary)
530
+ public func mentraBluetoothSDK(_ sdk: MentraBluetoothSDK, didUpdateGlasses _: GlassesRuntimeState) {
531
+ sendEvent("glasses_status", sdk.glassesStatus.dictionary)
532
532
  }
533
533
 
534
534
  @MainActor
535
- public func mentraBluetoothSDK(_: MentraBluetoothSDK, didUpdateBluetoothStatus status: BluetoothStatusUpdate) {
536
- sendEvent("bluetooth_status", status.values)
535
+ public func mentraBluetoothSDK(_ sdk: MentraBluetoothSDK, didUpdateSdkState _: PhoneSdkRuntimeState) {
536
+ sendEvent("bluetooth_status", sdk.bluetoothStatus.values)
537
537
  }
538
538
 
539
539
  @MainActor
@@ -589,13 +589,13 @@ public class BluetoothSdkModule: Module, MentraBluetoothSDKDelegate {
589
589
  }
590
590
 
591
591
  @MainActor
592
- public func mentraBluetoothSDK(_: MentraBluetoothSDK, didReceiveMicPcm frame: Data) {
593
- sendEvent("mic_pcm", ["pcm": frame])
592
+ public func mentraBluetoothSDK(_: MentraBluetoothSDK, didReceiveMicPcm event: MicPcmEvent) {
593
+ sendEvent("mic_pcm", event.values)
594
594
  }
595
595
 
596
596
  @MainActor
597
- public func mentraBluetoothSDK(_: MentraBluetoothSDK, didReceiveMicLc3 frame: Data) {
598
- sendEvent("mic_lc3", ["lc3": frame])
597
+ public func mentraBluetoothSDK(_: MentraBluetoothSDK, didReceiveMicLc3 event: MicLc3Event) {
598
+ sendEvent("mic_lc3", event.values)
599
599
  }
600
600
 
601
601
  @MainActor
@@ -0,0 +1,159 @@
1
+ import Foundation
2
+
3
+ public enum MicPreference: String {
4
+ case auto
5
+ case phone
6
+ case glasses
7
+ case bluetooth
8
+ }
9
+
10
+ public struct LocalTranscriptionEvent: CustomStringConvertible {
11
+ public let text: String
12
+ public let isFinal: Bool
13
+ public let values: [String: Any]
14
+
15
+ public init(text: String, isFinal: Bool, values: [String: Any]) {
16
+ self.text = text
17
+ self.isFinal = isFinal
18
+ self.values = values
19
+ }
20
+
21
+ public var description: String {
22
+ "LocalTranscriptionEvent(text: \(text), isFinal: \(isFinal))"
23
+ }
24
+ }
25
+
26
+ public struct MicPcmEvent: CustomStringConvertible {
27
+ public static let sampleRate = 16_000
28
+ public static let bitsPerSample = 16
29
+ public static let channels = 1
30
+ public static let encoding = "pcm_s16le"
31
+
32
+ public let pcm: Data
33
+ public let sampleRate: Int
34
+ public let bitsPerSample: Int
35
+ public let channels: Int
36
+ public let encoding: String
37
+ public let vadGated: Bool
38
+ public let values: [String: Any]
39
+
40
+ public init(values: [String: Any]) {
41
+ let pcm = values["pcm"] as? Data ?? Data()
42
+ let sampleRate = intValue(values["sampleRate"]) ?? Self.sampleRate
43
+ let bitsPerSample = intValue(values["bitsPerSample"]) ?? Self.bitsPerSample
44
+ let channels = intValue(values["channels"]) ?? Self.channels
45
+ let encoding = values["encoding"] as? String ?? Self.encoding
46
+ let vadGated = boolValue(values, "vadGated") ?? false
47
+
48
+ var normalized = values
49
+ normalized["type"] = "mic_pcm"
50
+ normalized["pcm"] = pcm
51
+ normalized["sampleRate"] = sampleRate
52
+ normalized["bitsPerSample"] = bitsPerSample
53
+ normalized["channels"] = channels
54
+ normalized["encoding"] = encoding
55
+ normalized["vadGated"] = vadGated
56
+
57
+ self.pcm = pcm
58
+ self.sampleRate = sampleRate
59
+ self.bitsPerSample = bitsPerSample
60
+ self.channels = channels
61
+ self.encoding = encoding
62
+ self.vadGated = vadGated
63
+ self.values = normalized
64
+ }
65
+
66
+ public var description: String {
67
+ "MicPcmEvent(bytes: \(pcm.count), sampleRate: \(sampleRate), bitsPerSample: \(bitsPerSample), channels: \(channels), encoding: \(encoding), vadGated: \(vadGated))"
68
+ }
69
+ }
70
+
71
+ public struct MicLc3Event: CustomStringConvertible {
72
+ public static let sampleRate = 16_000
73
+ public static let channels = 1
74
+ public static let encoding = "lc3"
75
+ public static let frameDurationMs = 10
76
+ public static let defaultFrameSizeBytes = 60
77
+
78
+ public let lc3: Data
79
+ public let sampleRate: Int
80
+ public let channels: Int
81
+ public let encoding: String
82
+ public let frameDurationMs: Int
83
+ public let frameSizeBytes: Int
84
+ public let bitrate: Int
85
+ public let packetizedFromGlasses: Bool
86
+ public let vadGated: Bool
87
+ public let values: [String: Any]
88
+
89
+ public init(values: [String: Any]) {
90
+ let lc3 = values["lc3"] as? Data ?? Data()
91
+ let sampleRate = intValue(values["sampleRate"]) ?? Self.sampleRate
92
+ let channels = intValue(values["channels"]) ?? Self.channels
93
+ let encoding = values["encoding"] as? String ?? Self.encoding
94
+ let frameDurationMs = intValue(values["frameDurationMs"]) ?? Self.frameDurationMs
95
+ let frameSizeBytes = intValue(values["frameSizeBytes"]) ?? Self.defaultFrameSizeBytes
96
+ let bitrate = intValue(values["bitrate"]) ?? frameSizeBytes * 8 * (1000 / frameDurationMs)
97
+ let packetizedFromGlasses = boolValue(values, "packetizedFromGlasses") ?? false
98
+ let vadGated = boolValue(values, "vadGated") ?? false
99
+
100
+ var normalized = values
101
+ normalized["type"] = "mic_lc3"
102
+ normalized["lc3"] = lc3
103
+ normalized["sampleRate"] = sampleRate
104
+ normalized["channels"] = channels
105
+ normalized["encoding"] = encoding
106
+ normalized["frameDurationMs"] = frameDurationMs
107
+ normalized["frameSizeBytes"] = frameSizeBytes
108
+ normalized["bitrate"] = bitrate
109
+ normalized["packetizedFromGlasses"] = packetizedFromGlasses
110
+ normalized["vadGated"] = vadGated
111
+
112
+ self.lc3 = lc3
113
+ self.sampleRate = sampleRate
114
+ self.channels = channels
115
+ self.encoding = encoding
116
+ self.frameDurationMs = frameDurationMs
117
+ self.frameSizeBytes = frameSizeBytes
118
+ self.bitrate = bitrate
119
+ self.packetizedFromGlasses = packetizedFromGlasses
120
+ self.vadGated = vadGated
121
+ self.values = normalized
122
+ }
123
+
124
+ public var description: String {
125
+ "MicLc3Event(bytes: \(lc3.count), sampleRate: \(sampleRate), channels: \(channels), frameDurationMs: \(frameDurationMs), frameSizeBytes: \(frameSizeBytes), bitrate: \(bitrate), packetizedFromGlasses: \(packetizedFromGlasses), vadGated: \(vadGated))"
126
+ }
127
+ }
128
+
129
+ public struct GlassesMediaVolumeGetResult: CustomStringConvertible {
130
+ public let level: Int?
131
+ public let statusCode: Int?
132
+ public let values: [String: Any]
133
+
134
+ public init(values: [String: Any]) {
135
+ self.level = intValue(values["level"])
136
+ self.statusCode = intValue(values["statusCode"])
137
+ self.values = values
138
+ }
139
+
140
+ public var description: String {
141
+ let levelText = level.map(String.init) ?? "unknown"
142
+ let statusCodeText = statusCode.map(String.init) ?? "unknown"
143
+ return "GlassesMediaVolumeGetResult(level: \(levelText), statusCode: \(statusCodeText))"
144
+ }
145
+ }
146
+
147
+ public struct GlassesMediaVolumeSetResult: CustomStringConvertible {
148
+ public let statusCode: Int?
149
+ public let values: [String: Any]
150
+
151
+ public init(values: [String: Any]) {
152
+ self.statusCode = intValue(values["statusCode"])
153
+ self.values = values
154
+ }
155
+
156
+ public var description: String {
157
+ "GlassesMediaVolumeSetResult(statusCode: \(statusCode.map(String.init) ?? "unknown"))"
158
+ }
159
+ }