@mentra/bluetooth-sdk 0.1.18 → 0.1.20
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 +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +135 -51
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceManager.kt +120 -17
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +5 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +34 -21
- package/android/src/main/java/com/mentra/bluetoothsdk/OtaManifest.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +13 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1.kt +1 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G1TextSanitizer.kt +38 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/G2.kt +488 -15
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLive.kt +551 -159
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraLiveL2capChannel.kt +274 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraNex.kt +361 -67
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/MentraosBle.java +7501 -3704
- package/android/src/main/java/com/mentra/bluetoothsdk/sgcs/SGCManager.kt +134 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +0 -6
- package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +2 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BleJsonCompact.java +493 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadService.java +65 -5
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/BleWireProtocol.java +108 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/IncidentLogBleUploadService.java +4 -3
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900LengthCodec.java +115 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtils.java +109 -73
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunkReassembler.java +106 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/MessageChunker.java +93 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/utils/NexSGCUtils.kt +111 -11
- package/android/src/test/java/com/mentra/bluetoothsdk/BluetoothSdkExceptionTest.kt +18 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/camera/PhotoRequestTest.kt +23 -9
- package/android/src/test/java/com/mentra/bluetoothsdk/sgcs/G1TextSanitizerTest.kt +31 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/AvifExifStripperTest.java +17 -1
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/BinaryMessageChunkerTest.java +84 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/BleJsonCompactTest.java +158 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/BlePhotoUploadServiceTest.java +9 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtilsEndiannessTest.java +172 -0
- package/android/src/test/java/com/mentra/bluetoothsdk/utils/K900ProtocolUtilsTest.java +24 -0
- package/build/BluetoothSdk.types.d.ts +37 -1
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +4 -0
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/_private/photoRequestPayload.d.ts.map +1 -1
- package/build/_private/photoRequestPayload.js +1 -0
- package/build/_private/photoRequestPayload.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +5 -0
- package/build/index.js.map +1 -1
- package/build/types/index.d.ts +3 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/ios/Source/BluetoothSdkDefaults.swift +1 -1
- package/ios/Source/DeviceManager.swift +136 -30
- package/ios/Source/DeviceStore.swift +5 -5
- package/ios/Source/MentraBluetoothSDK.swift +40 -24
- package/ios/Source/OtaManifest.swift +1 -1
- package/ios/Source/camera/CameraModels.swift +17 -3
- package/ios/Source/sgcs/G1.swift +1 -1
- package/ios/Source/sgcs/G2.swift +518 -11
- package/ios/Source/sgcs/MentraLive.swift +443 -42
- package/ios/Source/sgcs/MentraLiveL2capChannel.swift +183 -0
- package/ios/Source/sgcs/MentraNex.swift +416 -32
- package/ios/Source/sgcs/SGCManager.swift +155 -0
- package/ios/Source/sgcs/mentraos_ble.pb.swift +726 -122
- package/ios/Source/status/DeviceStatus.swift +0 -8
- package/ios/Source/utils/BleJsonCompact.swift +395 -0
- package/ios/Source/utils/BleWireProtocol.swift +92 -0
- package/ios/Source/utils/G1Text.swift +30 -1
- package/ios/Source/utils/MessageChunkReassembler.swift +82 -0
- package/ios/Source/utils/MessageChunker.swift +73 -0
- package/package.json +14 -7
- package/src/BluetoothSdk.types.ts +39 -1
- package/src/_private/BluetoothSdkModule.ts +4 -0
- package/src/_private/photoRequestPayload.ts +1 -0
- package/src/index.ts +6 -0
- package/src/types/index.ts +7 -0
|
@@ -24,6 +24,8 @@ class MessageChunker {
|
|
|
24
24
|
private static let MIN_CHUNK_DATA_SIZE = 4
|
|
25
25
|
private static let MAX_PACKED_CHUNK_SIZE = 253
|
|
26
26
|
private static let K900_FRAME_OVERHEAD = 7
|
|
27
|
+
private static let MAX_BINARY_FRAGMENT_PAYLOAD = BleWireProtocol.maxFragmentPayload
|
|
28
|
+
private static let MAX_BINARY_FRAME_SIZE = BleWireProtocol.mtuTarget
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
* Check if a message needs to be chunked
|
|
@@ -204,6 +206,77 @@ class MessageChunker {
|
|
|
204
206
|
)
|
|
205
207
|
}
|
|
206
208
|
|
|
209
|
+
static func needsBinaryFragmenting(_ payload: Data) -> Bool {
|
|
210
|
+
payload.count > MAX_BINARY_FRAGMENT_PAYLOAD
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
static func needsBinaryFragmenting(_ json: String) -> Bool {
|
|
214
|
+
guard let data = json.data(using: .utf8) else { return false }
|
|
215
|
+
return needsBinaryFragmenting(data)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
struct BinaryFragment {
|
|
219
|
+
let flags: UInt8
|
|
220
|
+
let msgId: UInt16
|
|
221
|
+
let fragIdx: UInt8
|
|
222
|
+
let fragCount: UInt8
|
|
223
|
+
let payload: Data
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
static func createBinaryFragments(
|
|
227
|
+
payload: Data,
|
|
228
|
+
msgId: UInt16 = 0,
|
|
229
|
+
wakeUp: Bool = false,
|
|
230
|
+
ackRequested: Bool = false
|
|
231
|
+
) -> [BinaryFragment] {
|
|
232
|
+
let fragCount = max(1, (payload.count + MAX_BINARY_FRAGMENT_PAYLOAD - 1) / MAX_BINARY_FRAGMENT_PAYLOAD)
|
|
233
|
+
guard fragCount <= 255 else { return [] }
|
|
234
|
+
|
|
235
|
+
var fragments: [BinaryFragment] = []
|
|
236
|
+
for i in 0 ..< fragCount {
|
|
237
|
+
let offset = i * MAX_BINARY_FRAGMENT_PAYLOAD
|
|
238
|
+
let end = min(offset + MAX_BINARY_FRAGMENT_PAYLOAD, payload.count)
|
|
239
|
+
let fragPayload = payload.subdata(in: offset ..< end)
|
|
240
|
+
|
|
241
|
+
var flags: UInt8 = 0
|
|
242
|
+
if i == 0 { flags |= BleWireProtocol.flagFirstFrag }
|
|
243
|
+
if i == fragCount - 1 { flags |= BleWireProtocol.flagLastFrag }
|
|
244
|
+
if wakeUp, i == 0 { flags |= BleWireProtocol.flagWake }
|
|
245
|
+
if ackRequested, i == fragCount - 1 { flags |= BleWireProtocol.flagAckRequested }
|
|
246
|
+
|
|
247
|
+
fragments.append(
|
|
248
|
+
BinaryFragment(
|
|
249
|
+
flags: flags,
|
|
250
|
+
msgId: msgId,
|
|
251
|
+
fragIdx: UInt8(i),
|
|
252
|
+
fragCount: UInt8(fragCount),
|
|
253
|
+
payload: fragPayload
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
print("MessageChunker: Created \(fragments.count) binary fragments for \(payload.count) bytes")
|
|
259
|
+
return fragments
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
static func allBinaryFragmentsFit(_ fragments: [BinaryFragment]) -> Bool {
|
|
263
|
+
for fragment in fragments {
|
|
264
|
+
guard let packed = BleWireProtocol.packBinaryFragment(
|
|
265
|
+
flags: fragment.flags,
|
|
266
|
+
msgId: fragment.msgId,
|
|
267
|
+
fragIdx: fragment.fragIdx,
|
|
268
|
+
fragCount: fragment.fragCount,
|
|
269
|
+
payload: fragment.payload
|
|
270
|
+
) else {
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
if packed.count > MAX_BINARY_FRAME_SIZE {
|
|
274
|
+
return false
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return true
|
|
278
|
+
}
|
|
279
|
+
|
|
207
280
|
/**
|
|
208
281
|
* Container for chunk information
|
|
209
282
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/bluetooth-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20",
|
|
4
4
|
"description": "SDK for communicating with smart glasses",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -8,28 +8,33 @@
|
|
|
8
8
|
"types": "build/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"types": "./build/index.d.ts",
|
|
12
11
|
"react-native": "./src/index.ts",
|
|
12
|
+
"types": "./build/index.d.ts",
|
|
13
13
|
"default": "./build/index.js"
|
|
14
14
|
},
|
|
15
15
|
"./internal": {
|
|
16
|
-
"types": "./build/_internal.d.ts",
|
|
17
16
|
"react-native": "./src/_internal.ts",
|
|
17
|
+
"types": "./build/_internal.d.ts",
|
|
18
18
|
"default": "./build/_internal.js"
|
|
19
19
|
},
|
|
20
20
|
"./react": {
|
|
21
|
-
"types": "./build/react/index.d.ts",
|
|
22
21
|
"react-native": "./src/react/index.ts",
|
|
22
|
+
"types": "./build/react/index.d.ts",
|
|
23
23
|
"default": "./build/react/index.js"
|
|
24
24
|
},
|
|
25
|
+
"./types": {
|
|
26
|
+
"react-native": "./src/types/index.ts",
|
|
27
|
+
"types": "./build/types/index.d.ts",
|
|
28
|
+
"default": "./build/types/index.js"
|
|
29
|
+
},
|
|
25
30
|
"./photo-receiver": {
|
|
26
|
-
"types": "./build/photo-receiver/index.d.ts",
|
|
27
31
|
"react-native": "./src/photo-receiver/index.ts",
|
|
32
|
+
"types": "./build/photo-receiver/index.d.ts",
|
|
28
33
|
"default": "./build/photo-receiver/index.js"
|
|
29
34
|
},
|
|
30
35
|
"./debug": {
|
|
31
|
-
"types": "./build/debug.d.ts",
|
|
32
36
|
"react-native": "./src/debug.ts",
|
|
37
|
+
"types": "./build/debug.d.ts",
|
|
33
38
|
"default": "./build/debug.js"
|
|
34
39
|
},
|
|
35
40
|
"./_private/*": null,
|
|
@@ -102,7 +107,9 @@
|
|
|
102
107
|
},
|
|
103
108
|
"dependencies": {},
|
|
104
109
|
"devDependencies": {
|
|
105
|
-
"
|
|
110
|
+
"@types/node": "^25.9.3",
|
|
111
|
+
"expo-module-scripts": "^55.0.2",
|
|
112
|
+
"typescript": "~5.9.2"
|
|
106
113
|
},
|
|
107
114
|
"peerDependencies": {
|
|
108
115
|
"@expo/config-plugins": ">=8.0.0",
|
|
@@ -440,8 +440,14 @@ export type SettingsAckSuccessEvent = Omit<SettingsAckEvent, "status"> & {
|
|
|
440
440
|
export type RgbLedAction = "on" | "off"
|
|
441
441
|
export type RgbLedColor = "red" | "green" | "blue" | "orange" | "white"
|
|
442
442
|
export type PhotoSize = "low" | "medium" | "high" | "max"
|
|
443
|
+
export type PhotoMode = "photo" | "text"
|
|
443
444
|
export type ButtonPhotoSize = "low" | "medium" | "high" | "max"
|
|
444
445
|
|
|
446
|
+
/**
|
|
447
|
+
* @deprecated Sticky action-button photo presets via {@link BluetoothSdkPublicModule.setPhotoCaptureDefaults}
|
|
448
|
+
* are deprecated. Prefer per-request {@link BluetoothSdkPublicModule.requestPhoto} options
|
|
449
|
+
* (e.g. `mode: "text"` for AE ÷3) instead of persisting button-photo tuning on the glasses.
|
|
450
|
+
*/
|
|
445
451
|
export type PhotoCaptureDefaults = {
|
|
446
452
|
size?: PhotoSize
|
|
447
453
|
mfnr?: boolean
|
|
@@ -542,7 +548,9 @@ export type MicMode = "phone" | "glasses" | "bluetoothClassic" | "bluetooth"
|
|
|
542
548
|
|
|
543
549
|
export type PhotoRequestParams = {
|
|
544
550
|
requestId?: string
|
|
551
|
+
appId?: string
|
|
545
552
|
size: PhotoSize
|
|
553
|
+
mode?: PhotoMode
|
|
546
554
|
webhookUrl: string | null
|
|
547
555
|
authToken: string | null
|
|
548
556
|
compress: PhotoCompression
|
|
@@ -689,11 +697,25 @@ export type StreamResolvedConfig = {
|
|
|
689
697
|
}
|
|
690
698
|
}
|
|
691
699
|
|
|
700
|
+
/** Live encoder telemetry, when the glasses emit it (no firmware does yet). */
|
|
701
|
+
export type StreamLiveStats = {
|
|
702
|
+
/** Current encoded video bitrate in bits per second. */
|
|
703
|
+
bitrate?: number
|
|
704
|
+
/** Current encode frame rate. */
|
|
705
|
+
fps?: number
|
|
706
|
+
droppedFrames?: number
|
|
707
|
+
/** Seconds since the stream started. */
|
|
708
|
+
duration?: number
|
|
709
|
+
/** Device temperature in °C, if the hardware reports it. */
|
|
710
|
+
temperatureC?: number
|
|
711
|
+
}
|
|
712
|
+
|
|
692
713
|
type StreamStatusCommon = {
|
|
693
714
|
type: "stream_status"
|
|
694
715
|
streamId?: string
|
|
695
716
|
timestamp?: number
|
|
696
717
|
resolvedConfig?: StreamResolvedConfig
|
|
718
|
+
stats?: StreamLiveStats
|
|
697
719
|
}
|
|
698
720
|
|
|
699
721
|
export type StreamStatusEvent =
|
|
@@ -761,6 +783,15 @@ export type OtaStartAckEvent = {
|
|
|
761
783
|
timestamp: number
|
|
762
784
|
}
|
|
763
785
|
|
|
786
|
+
export type OtaUpdateAvailableEvent = {
|
|
787
|
+
type: "ota_update_available"
|
|
788
|
+
version_code?: number
|
|
789
|
+
version_name?: string
|
|
790
|
+
updates?: string[]
|
|
791
|
+
total_size?: number
|
|
792
|
+
cache_ready?: boolean
|
|
793
|
+
}
|
|
794
|
+
|
|
764
795
|
export type OtaStatusEvent = {
|
|
765
796
|
type: "ota_status"
|
|
766
797
|
session_id: string
|
|
@@ -837,6 +868,7 @@ export type BluetoothSdkModuleEvents = {
|
|
|
837
868
|
stream_status: (event: StreamStatusEvent) => void
|
|
838
869
|
keep_alive_ack: (event: KeepAliveAckEvent) => void
|
|
839
870
|
mtk_update_complete: (event: MtkUpdateCompleteEvent) => void
|
|
871
|
+
ota_update_available: (event: OtaUpdateAvailableEvent) => void
|
|
840
872
|
ota_start_ack: (event: OtaStartAckEvent) => void
|
|
841
873
|
ota_status: (event: OtaStatusEvent) => void
|
|
842
874
|
version_info: (event: VersionInfoEvent) => void
|
|
@@ -907,6 +939,7 @@ export type BluetoothSdkEventMap = {
|
|
|
907
939
|
mic_pcm: MicPcmEvent
|
|
908
940
|
mic_lc3: MicLc3Event
|
|
909
941
|
stream_status: StreamStatusEvent
|
|
942
|
+
ota_update_available: OtaUpdateAvailableEvent
|
|
910
943
|
ota_start_ack: OtaStartAckEvent
|
|
911
944
|
ota_status: OtaStatusEvent
|
|
912
945
|
version_info: VersionInfoEvent
|
|
@@ -960,6 +993,11 @@ export interface BluetoothSdkPublicModule {
|
|
|
960
993
|
|
|
961
994
|
setGalleryModeEnabled(enabled: boolean): Promise<SettingsAckSuccessEvent>
|
|
962
995
|
setVoiceActivityDetectionEnabled(enabled: boolean): Promise<void>
|
|
996
|
+
/**
|
|
997
|
+
* @deprecated Sticky action-button photo presets are deprecated. Prefer per-request
|
|
998
|
+
* `requestPhoto(...)` options (e.g. `mode: "text"` for AE ÷3, or explicit per-shot
|
|
999
|
+
* fields). Still functional until removed in a future release.
|
|
1000
|
+
*/
|
|
963
1001
|
setPhotoCaptureDefaults(settings: PhotoCaptureDefaults): Promise<SettingsAckSuccessEvent>
|
|
964
1002
|
setVideoRecordingDefaults(settings: VideoRecordingDefaults): Promise<SettingsAckSuccessEvent>
|
|
965
1003
|
setMaxVideoRecordingDuration(minutes: number): Promise<SettingsAckSuccessEvent>
|
|
@@ -1085,6 +1123,7 @@ export interface OtaUpdateInfo {
|
|
|
1085
1123
|
versionName: string
|
|
1086
1124
|
updates: string[] // ["apk", "mtk", "bes"]
|
|
1087
1125
|
totalSize: number
|
|
1126
|
+
cacheReady?: boolean
|
|
1088
1127
|
}
|
|
1089
1128
|
|
|
1090
1129
|
export interface OtaProgress {
|
|
@@ -1270,7 +1309,6 @@ export type BluetoothSettingsUpdate = Partial<{
|
|
|
1270
1309
|
should_send_lc3: boolean
|
|
1271
1310
|
should_send_transcript: boolean
|
|
1272
1311
|
offline_mode: boolean
|
|
1273
|
-
offline_captions_running: boolean
|
|
1274
1312
|
local_stt_fallback_active: boolean
|
|
1275
1313
|
pending_wearable: DeviceModel | ""
|
|
1276
1314
|
default_wearable: DeviceModel | ""
|
|
@@ -124,6 +124,10 @@ declare class BluetoothSdkNativeModule extends NativeModule<BluetoothSdkModuleEv
|
|
|
124
124
|
// Gallery Commands
|
|
125
125
|
setGalleryModeEnabled(enabled: boolean): Promise<SettingsAckSuccessEvent>
|
|
126
126
|
setVoiceActivityDetectionEnabled(enabled: boolean): Promise<void>
|
|
127
|
+
/**
|
|
128
|
+
* @deprecated Sticky action-button photo presets are deprecated. Prefer per-request
|
|
129
|
+
* `requestPhoto(...)` options (e.g. `mode: "text"` for AE ÷3).
|
|
130
|
+
*/
|
|
127
131
|
setPhotoCaptureDefaults(settings: PhotoCaptureDefaults): Promise<SettingsAckSuccessEvent>
|
|
128
132
|
setVideoRecordingDefaults(width: number, height: number, fps: number): Promise<SettingsAckSuccessEvent>
|
|
129
133
|
setMaxVideoRecordingDuration(minutes: number): Promise<SettingsAckSuccessEvent>
|
|
@@ -30,6 +30,7 @@ export function photoRequestParamsForNative(
|
|
|
30
30
|
): Record<string, string | number | boolean> {
|
|
31
31
|
const payload: Record<string, string | number | boolean> = {
|
|
32
32
|
size: normalizePhotoSizeTier(params.size),
|
|
33
|
+
mode: params.mode ?? "photo",
|
|
33
34
|
webhookUrl: params.webhookUrl ?? "",
|
|
34
35
|
compress: params.compress,
|
|
35
36
|
sound: params.sound,
|
package/src/index.ts
CHANGED
|
@@ -96,6 +96,11 @@ export const BluetoothSdk: BluetoothSdkPublicModule = Object.freeze({
|
|
|
96
96
|
setHotspotState: bindPublicMethod("setHotspotState"),
|
|
97
97
|
setGalleryModeEnabled: bindPublicMethod("setGalleryModeEnabled"),
|
|
98
98
|
setVoiceActivityDetectionEnabled: bindPublicMethod("setVoiceActivityDetectionEnabled"),
|
|
99
|
+
/**
|
|
100
|
+
* @deprecated Sticky action-button photo presets are deprecated. Prefer per-request
|
|
101
|
+
* `requestPhoto(...)` options (e.g. `mode: "text"` for AE ÷3, or explicit per-shot
|
|
102
|
+
* fields). Still functional until removed in a future release.
|
|
103
|
+
*/
|
|
99
104
|
setPhotoCaptureDefaults: bindPublicMethod("setPhotoCaptureDefaults"),
|
|
100
105
|
setVideoRecordingDefaults: ({width, height, fps}: VideoRecordingDefaults) => {
|
|
101
106
|
const method = (PrivateBluetoothSdkModule as unknown as Record<string, unknown>).setVideoRecordingDefaults
|
|
@@ -204,6 +209,7 @@ export type {
|
|
|
204
209
|
PhotoCompression,
|
|
205
210
|
PhotoFpsRange,
|
|
206
211
|
PhotoMeteredPreview,
|
|
212
|
+
PhotoMode,
|
|
207
213
|
PhotoResponseEvent,
|
|
208
214
|
PhotoRequestedCaptureConfig,
|
|
209
215
|
PhotoRequestParams,
|