@mentra/miniapp 0.3.0-beta.0
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 +259 -0
- package/dist/background/index.d.ts +60 -0
- package/dist/background/index.d.ts.map +1 -0
- package/dist/background/index.js +25 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/register.d.ts +38 -0
- package/dist/background/register.d.ts.map +1 -0
- package/dist/background/register.js +75 -0
- package/dist/background/register.js.map +1 -0
- package/dist/dev-reload.d.ts +21 -0
- package/dist/dev-reload.d.ts.map +1 -0
- package/dist/dev-reload.js +62 -0
- package/dist/dev-reload.js.map +1 -0
- package/dist/envelope.d.ts +23 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +47 -0
- package/dist/envelope.js.map +1 -0
- package/dist/globals.d.ts +54 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +12 -0
- package/dist/globals.js.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/actions.d.ts +54 -0
- package/dist/modules/actions.d.ts.map +1 -0
- package/dist/modules/actions.js +122 -0
- package/dist/modules/actions.js.map +1 -0
- package/dist/modules/auth.d.ts +25 -0
- package/dist/modules/auth.d.ts.map +1 -0
- package/dist/modules/auth.js +52 -0
- package/dist/modules/auth.js.map +1 -0
- package/dist/modules/base64.d.ts +16 -0
- package/dist/modules/base64.d.ts.map +1 -0
- package/dist/modules/base64.js +92 -0
- package/dist/modules/base64.js.map +1 -0
- package/dist/modules/blob.d.ts +161 -0
- package/dist/modules/blob.d.ts.map +1 -0
- package/dist/modules/blob.js +277 -0
- package/dist/modules/blob.js.map +1 -0
- package/dist/modules/camera.d.ts +170 -0
- package/dist/modules/camera.d.ts.map +1 -0
- package/dist/modules/camera.js +116 -0
- package/dist/modules/camera.js.map +1 -0
- package/dist/modules/cloud.d.ts +34 -0
- package/dist/modules/cloud.d.ts.map +1 -0
- package/dist/modules/cloud.js +70 -0
- package/dist/modules/cloud.js.map +1 -0
- package/dist/modules/dashboard.d.ts +16 -0
- package/dist/modules/dashboard.d.ts.map +1 -0
- package/dist/modules/dashboard.js +27 -0
- package/dist/modules/dashboard.js.map +1 -0
- package/dist/modules/display.d.ts +106 -0
- package/dist/modules/display.d.ts.map +1 -0
- package/dist/modules/display.js +57 -0
- package/dist/modules/display.js.map +1 -0
- package/dist/modules/events.d.ts +160 -0
- package/dist/modules/events.d.ts.map +1 -0
- package/dist/modules/events.js +168 -0
- package/dist/modules/events.js.map +1 -0
- package/dist/modules/glasses.d.ts +28 -0
- package/dist/modules/glasses.d.ts.map +1 -0
- package/dist/modules/glasses.js +39 -0
- package/dist/modules/glasses.js.map +1 -0
- package/dist/modules/heading.d.ts +16 -0
- package/dist/modules/heading.d.ts.map +1 -0
- package/dist/modules/heading.js +20 -0
- package/dist/modules/heading.js.map +1 -0
- package/dist/modules/imu.d.ts +31 -0
- package/dist/modules/imu.d.ts.map +1 -0
- package/dist/modules/imu.js +40 -0
- package/dist/modules/imu.js.map +1 -0
- package/dist/modules/input.d.ts +34 -0
- package/dist/modules/input.d.ts.map +1 -0
- package/dist/modules/input.js +50 -0
- package/dist/modules/input.js.map +1 -0
- package/dist/modules/led.d.ts +35 -0
- package/dist/modules/led.d.ts.map +1 -0
- package/dist/modules/led.js +39 -0
- package/dist/modules/led.js.map +1 -0
- package/dist/modules/location.d.ts +27 -0
- package/dist/modules/location.d.ts.map +1 -0
- package/dist/modules/location.js +35 -0
- package/dist/modules/location.js.map +1 -0
- package/dist/modules/mic.d.ts +44 -0
- package/dist/modules/mic.d.ts.map +1 -0
- package/dist/modules/mic.js +67 -0
- package/dist/modules/mic.js.map +1 -0
- package/dist/modules/miniapps.d.ts +72 -0
- package/dist/modules/miniapps.d.ts.map +1 -0
- package/dist/modules/miniapps.js +48 -0
- package/dist/modules/miniapps.js.map +1 -0
- package/dist/modules/navigation.d.ts +326 -0
- package/dist/modules/navigation.d.ts.map +1 -0
- package/dist/modules/navigation.js +386 -0
- package/dist/modules/navigation.js.map +1 -0
- package/dist/modules/permissions.d.ts +58 -0
- package/dist/modules/permissions.d.ts.map +1 -0
- package/dist/modules/permissions.js +66 -0
- package/dist/modules/permissions.js.map +1 -0
- package/dist/modules/phone.d.ts +95 -0
- package/dist/modules/phone.d.ts.map +1 -0
- package/dist/modules/phone.js +110 -0
- package/dist/modules/phone.js.map +1 -0
- package/dist/modules/pivots/engine.d.ts +169 -0
- package/dist/modules/pivots/engine.d.ts.map +1 -0
- package/dist/modules/pivots/engine.js +779 -0
- package/dist/modules/pivots/engine.js.map +1 -0
- package/dist/modules/pivots/geometry.d.ts +84 -0
- package/dist/modules/pivots/geometry.d.ts.map +1 -0
- package/dist/modules/pivots/geometry.js +371 -0
- package/dist/modules/pivots/geometry.js.map +1 -0
- package/dist/modules/pivots/instructions.d.ts +139 -0
- package/dist/modules/pivots/instructions.d.ts.map +1 -0
- package/dist/modules/pivots/instructions.js +280 -0
- package/dist/modules/pivots/instructions.js.map +1 -0
- package/dist/modules/speaker.d.ts +169 -0
- package/dist/modules/speaker.d.ts.map +1 -0
- package/dist/modules/speaker.js +251 -0
- package/dist/modules/speaker.js.map +1 -0
- package/dist/modules/storage.d.ts +50 -0
- package/dist/modules/storage.d.ts.map +1 -0
- package/dist/modules/storage.js +99 -0
- package/dist/modules/storage.js.map +1 -0
- package/dist/modules/stream.d.ts +129 -0
- package/dist/modules/stream.d.ts.map +1 -0
- package/dist/modules/stream.js +52 -0
- package/dist/modules/stream.js.map +1 -0
- package/dist/modules/system.d.ts +45 -0
- package/dist/modules/system.d.ts.map +1 -0
- package/dist/modules/system.js +42 -0
- package/dist/modules/system.js.map +1 -0
- package/dist/modules/transcription.d.ts +75 -0
- package/dist/modules/transcription.d.ts.map +1 -0
- package/dist/modules/transcription.js +106 -0
- package/dist/modules/transcription.js.map +1 -0
- package/dist/modules/translation.d.ts +59 -0
- package/dist/modules/translation.d.ts.map +1 -0
- package/dist/modules/translation.js +119 -0
- package/dist/modules/translation.js.map +1 -0
- package/dist/modules/ui.d.ts +186 -0
- package/dist/modules/ui.d.ts.map +1 -0
- package/dist/modules/ui.js +293 -0
- package/dist/modules/ui.js.map +1 -0
- package/dist/protocol.d.ts +299 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +325 -0
- package/dist/protocol.js.map +1 -0
- package/dist/react/MentraProvider.d.ts +33 -0
- package/dist/react/MentraProvider.d.ts.map +1 -0
- package/dist/react/MentraProvider.js +15 -0
- package/dist/react/MentraProvider.js.map +1 -0
- package/dist/react/MiniappHeader.d.ts +44 -0
- package/dist/react/MiniappHeader.d.ts.map +1 -0
- package/dist/react/MiniappHeader.js +32 -0
- package/dist/react/MiniappHeader.js.map +1 -0
- package/dist/react/index.d.ts +13 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +9 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/useCapabilities.d.ts +26 -0
- package/dist/react/useCapabilities.d.ts.map +1 -0
- package/dist/react/useCapabilities.js +27 -0
- package/dist/react/useCapabilities.js.map +1 -0
- package/dist/react/useCapsuleHeaderStyle.d.ts +27 -0
- package/dist/react/useCapsuleHeaderStyle.d.ts.map +1 -0
- package/dist/react/useCapsuleHeaderStyle.js +36 -0
- package/dist/react/useCapsuleHeaderStyle.js.map +1 -0
- package/dist/react/useColorScheme.d.ts +18 -0
- package/dist/react/useColorScheme.d.ts.map +1 -0
- package/dist/react/useColorScheme.js +24 -0
- package/dist/react/useColorScheme.js.map +1 -0
- package/dist/react/useConnected.d.ts +17 -0
- package/dist/react/useConnected.d.ts.map +1 -0
- package/dist/react/useConnected.js +39 -0
- package/dist/react/useConnected.js.map +1 -0
- package/dist/react/useRpc.d.ts +29 -0
- package/dist/react/useRpc.d.ts.map +1 -0
- package/dist/react/useRpc.js +82 -0
- package/dist/react/useRpc.js.map +1 -0
- package/dist/react/useSafeArea.d.ts +21 -0
- package/dist/react/useSafeArea.d.ts.map +1 -0
- package/dist/react/useSafeArea.js +22 -0
- package/dist/react/useSafeArea.js.map +1 -0
- package/dist/session.d.ts +312 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +653 -0
- package/dist/session.js.map +1 -0
- package/dist/sub-path-types.test-d.d.ts +28 -0
- package/dist/sub-path-types.test-d.d.ts.map +1 -0
- package/dist/sub-path-types.test-d.js +37 -0
- package/dist/sub-path-types.test-d.js.map +1 -0
- package/dist/transport/auto.d.ts +35 -0
- package/dist/transport/auto.d.ts.map +1 -0
- package/dist/transport/auto.js +125 -0
- package/dist/transport/auto.js.map +1 -0
- package/dist/transport/dispatch.d.ts +43 -0
- package/dist/transport/dispatch.d.ts.map +1 -0
- package/dist/transport/dispatch.js +91 -0
- package/dist/transport/dispatch.js.map +1 -0
- package/dist/transport/local-socket.d.ts +28 -0
- package/dist/transport/local-socket.d.ts.map +1 -0
- package/dist/transport/local-socket.js +80 -0
- package/dist/transport/local-socket.js.map +1 -0
- package/dist/transport/mock.d.ts +54 -0
- package/dist/transport/mock.d.ts.map +1 -0
- package/dist/transport/mock.js +207 -0
- package/dist/transport/mock.js.map +1 -0
- package/dist/transport/postmessage.d.ts +36 -0
- package/dist/transport/postmessage.d.ts.map +1 -0
- package/dist/transport/postmessage.js +78 -0
- package/dist/transport/postmessage.js.map +1 -0
- package/dist/transport/types.d.ts +25 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +11 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/ui/index.d.ts +98 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +32 -0
- package/dist/ui/index.js.map +1 -0
- package/package.json +84 -0
- package/src/background/index.ts +152 -0
- package/src/background/register.ts +85 -0
- package/src/dev-reload.ts +60 -0
- package/src/envelope.ts +54 -0
- package/src/globals.ts +62 -0
- package/src/index.ts +171 -0
- package/src/modules/actions.ts +156 -0
- package/src/modules/auth.ts +68 -0
- package/src/modules/base64.ts +87 -0
- package/src/modules/blob.ts +341 -0
- package/src/modules/camera.ts +242 -0
- package/src/modules/cloud.ts +94 -0
- package/src/modules/dashboard.ts +31 -0
- package/src/modules/display.ts +122 -0
- package/src/modules/events.ts +291 -0
- package/src/modules/glasses.ts +44 -0
- package/src/modules/heading.ts +23 -0
- package/src/modules/imu.ts +44 -0
- package/src/modules/input.ts +71 -0
- package/src/modules/led.ts +61 -0
- package/src/modules/location.ts +39 -0
- package/src/modules/mic.ts +74 -0
- package/src/modules/miniapps.ts +90 -0
- package/src/modules/navigation.ts +670 -0
- package/src/modules/permissions.ts +84 -0
- package/src/modules/phone.ts +155 -0
- package/src/modules/pivots/engine.ts +863 -0
- package/src/modules/pivots/geometry.ts +409 -0
- package/src/modules/pivots/instructions.ts +343 -0
- package/src/modules/speaker.ts +335 -0
- package/src/modules/storage.ts +109 -0
- package/src/modules/stream.ts +163 -0
- package/src/modules/system.ts +76 -0
- package/src/modules/transcription.ts +145 -0
- package/src/modules/translation.ts +149 -0
- package/src/modules/ui.ts +498 -0
- package/src/protocol.ts +378 -0
- package/src/react/MentraProvider.tsx +50 -0
- package/src/react/MiniappHeader.tsx +122 -0
- package/src/react/index.ts +12 -0
- package/src/react/useCapabilities.ts +29 -0
- package/src/react/useCapsuleHeaderStyle.ts +54 -0
- package/src/react/useColorScheme.ts +26 -0
- package/src/react/useConnected.ts +47 -0
- package/src/react/useRpc.ts +106 -0
- package/src/react/useSafeArea.ts +40 -0
- package/src/session.ts +886 -0
- package/src/sub-path-types.test-d.ts +49 -0
- package/src/transport/auto.ts +143 -0
- package/src/transport/dispatch.ts +106 -0
- package/src/transport/local-socket.ts +93 -0
- package/src/transport/mock.ts +251 -0
- package/src/transport/postmessage.ts +95 -0
- package/src/transport/types.ts +26 -0
- package/src/ui/index.ts +122 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Routes-API instruction parsing helpers for the pivot
|
|
3
|
+
* engine.
|
|
4
|
+
*
|
|
5
|
+
* The Routes REST API returns per-step `navigationInstruction.instructions`
|
|
6
|
+
* strings like "Turn left onto Octavia Blvd" that unambiguously name the
|
|
7
|
+
* road being entered. Parsing these is the most reliable way to label a
|
|
8
|
+
* turn — more reliable than `StepInfo.road` from the Android Nav SDK,
|
|
9
|
+
* which lags one step behind for the live currentStep + uses a destination
|
|
10
|
+
* placeholder for the arrival leg.
|
|
11
|
+
*
|
|
12
|
+
* Originally lived in the Navigation miniapp's NavigationPage.tsx; moved
|
|
13
|
+
* into the SDK so every miniapp using `navigation.onPivot()` gets the
|
|
14
|
+
* same accurate road names without having to re-implement the parser.
|
|
15
|
+
*
|
|
16
|
+
* All helpers are pure — no side effects, no shared state.
|
|
17
|
+
*/
|
|
18
|
+
import type { LatLng, ManeuverKind } from "../navigation";
|
|
19
|
+
/**
|
|
20
|
+
* Pull a short road name out of a Routes-API instruction string.
|
|
21
|
+
* Instructions look like:
|
|
22
|
+
* "Turn left onto Octavia Blvd"
|
|
23
|
+
* "Slight right onto Octavia St"
|
|
24
|
+
* "Turn right onto Haight St\nDestination will be on the right"
|
|
25
|
+
*
|
|
26
|
+
* Returns null when the parse fails (e.g. instruction is missing, the
|
|
27
|
+
* "onto" clause is absent, or the captured text contains another
|
|
28
|
+
* maneuver verb / direction word). Callers treat null as "no road
|
|
29
|
+
* name available" and hide the label.
|
|
30
|
+
*
|
|
31
|
+
* Only "onto" is matched here — `\bon\b` was previously used as a
|
|
32
|
+
* fallback for depart steps ("Head north on Market St") but it
|
|
33
|
+
* over-matched, capturing maneuver verbs from stacked instructions
|
|
34
|
+
* ("Turn left, then turn right on..."). The depart step is the
|
|
35
|
+
* very first step and is dropped by the slice(0, -1) loop before
|
|
36
|
+
* this parser is called anyway, so removing the fallback costs us
|
|
37
|
+
* nothing real.
|
|
38
|
+
*/
|
|
39
|
+
export declare function roadNameFromInstruction(instruction?: string | null): string | null;
|
|
40
|
+
export declare function sameRoad(a: string, b: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Coarse left/right classifier for a maneuver string. Collapses all
|
|
43
|
+
* left variants (TURN_LEFT, SLIGHT_LEFT, SHARP_LEFT, UTURN_LEFT) to
|
|
44
|
+
* "left" and the rights to "right". Returns null when the maneuver
|
|
45
|
+
* isn't a directional turn (STRAIGHT, NAME_CHANGE, ARRIVE, etc.).
|
|
46
|
+
*/
|
|
47
|
+
export declare function turnDirection(maneuver?: string | null): "left" | "right" | null;
|
|
48
|
+
export declare function bendAngleAt(points: LatLng[], junction: LatLng): number | null;
|
|
49
|
+
/**
|
|
50
|
+
* Signed polyline bend at a junction. Positive = right turn, negative
|
|
51
|
+
* = left turn, in [-180, 180]. Used to pick a pivot's left/right
|
|
52
|
+
* direction from geometry when the Routes API's first-step maneuver
|
|
53
|
+
* is misleading (e.g. a curb-alignment micro-jog labeled TURN_LEFT
|
|
54
|
+
* right before the real right turn off Hayes onto Gough).
|
|
55
|
+
*/
|
|
56
|
+
export declare function signedBendAt(points: LatLng[], junction: LatLng): number | null;
|
|
57
|
+
/**
|
|
58
|
+
* Minimum bend (degrees) for a junction to count as a real turn worth
|
|
59
|
+
* a pivot. Below this the route is effectively straight through the
|
|
60
|
+
* point; the Routes API may name it as a turn for legal/lane reasons
|
|
61
|
+
* but the user perceives no direction change.
|
|
62
|
+
*/
|
|
63
|
+
export declare const MIN_TURN_ANGLE_DEG = 30;
|
|
64
|
+
/**
|
|
65
|
+
* Shape of a Routes-API computed step (matches `ComputedRouteStep` in
|
|
66
|
+
* the navigation module). Re-declared locally to avoid a circular
|
|
67
|
+
* import; the field set this helper needs is small.
|
|
68
|
+
*/
|
|
69
|
+
type ComputedStep = {
|
|
70
|
+
lat: number;
|
|
71
|
+
lng: number;
|
|
72
|
+
endLat: number;
|
|
73
|
+
endLng: number;
|
|
74
|
+
distanceMeters: number;
|
|
75
|
+
maneuver?: ManeuverKind;
|
|
76
|
+
instruction?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Pre-resolved road name from the host's hybrid resolver (Phase 1).
|
|
79
|
+
* Preferred over `instruction` parsing when present — same parser
|
|
80
|
+
* runs host-side, just earlier in the pipeline. Older callers that
|
|
81
|
+
* only pass `instruction` still work via the parse fallback below.
|
|
82
|
+
*/
|
|
83
|
+
road?: string | null;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* A pivot derived from Routes-API computed steps. Carries the
|
|
87
|
+
* instruction-parsed road labels alongside the geometric corner,
|
|
88
|
+
* ready to be merged into the SDK's `Pivot` shape by the caller.
|
|
89
|
+
*
|
|
90
|
+
* `fromRoad` is required — we drop pivots whose entry road couldn't
|
|
91
|
+
* be parsed. `toRoad` is nullable because the LAST real turn before
|
|
92
|
+
* arrival has a known fromRoad but unknown toRoad (the arrival
|
|
93
|
+
* step's instruction is "Destination will be on the right", no road
|
|
94
|
+
* name in it). The pivot engine treats those nulls as candidates
|
|
95
|
+
* for the reverse-geocode fallback.
|
|
96
|
+
*/
|
|
97
|
+
export type InstructionPivot = {
|
|
98
|
+
lat: number;
|
|
99
|
+
lng: number;
|
|
100
|
+
fromRoad: string;
|
|
101
|
+
toRoad: string | null;
|
|
102
|
+
direction: "left" | "right" | null;
|
|
103
|
+
maneuver: ManeuverKind;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Derive accurate turn pivots from a Routes-API step list. Each
|
|
107
|
+
* computed step's `instruction` describes the maneuver that BEGINS
|
|
108
|
+
* that step ("Turn left onto Guerrero St"). A pivot sits at
|
|
109
|
+
* `step[i].end` — the junction where you leave step[i]'s road and
|
|
110
|
+
* turn onto step[i+1]'s road. So for each pair (step[i], step[i+1]):
|
|
111
|
+
*
|
|
112
|
+
* fromRoad = roadNameFromInstruction(step[i].instruction)
|
|
113
|
+
* toRoad = roadNameFromInstruction(step[i+1].instruction)
|
|
114
|
+
* anchor = (step[i].endLat, step[i].endLng)
|
|
115
|
+
* maneuver = step[i+1].maneuver (the actual turn type at the corner)
|
|
116
|
+
*
|
|
117
|
+
* A pivot survives these filters:
|
|
118
|
+
* 1. `fromRoad` parsed successfully from step[i]'s instruction.
|
|
119
|
+
* Drop the pivot otherwise — we don't know the road the user
|
|
120
|
+
* came from, and labeling the dot wouldn't make sense.
|
|
121
|
+
* 2. If `toRoad` parsed too, it must differ from `fromRoad` (drop
|
|
122
|
+
* "stay on same road" jogs). If `toRoad` failed to parse, keep
|
|
123
|
+
* the pivot with `toRoad: null` so the engine can recover it
|
|
124
|
+
* via reverse-geocode. This is what keeps the LAST real turn
|
|
125
|
+
* before arrival in the list — that step's instruction is
|
|
126
|
+
* "Destination will be on the right" with no road name, but
|
|
127
|
+
* the turn itself is real and the user needs to see it.
|
|
128
|
+
* 3. The drawn polyline bends ≥ MIN_TURN_ANGLE_DEG at the junction
|
|
129
|
+
* (drops phantom turns where the geometry is visually straight).
|
|
130
|
+
*
|
|
131
|
+
* The LAST step (the arrival leg itself) is dropped by slice(0, -1) —
|
|
132
|
+
* the destination isn't a turn.
|
|
133
|
+
*
|
|
134
|
+
* Mirrors the Navigation miniapp's preview-turn extraction so live
|
|
135
|
+
* pivots match preview accuracy.
|
|
136
|
+
*/
|
|
137
|
+
export declare function extractPivotsFromComputedSteps(steps: ComputedStep[] | undefined, polyline: LatLng[]): InstructionPivot[];
|
|
138
|
+
export {};
|
|
139
|
+
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../../src/modules/pivots/instructions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAC,MAAM,EAAE,YAAY,EAAC,MAAM,eAAe,CAAA;AAqBvD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CA0BlF;AAaD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAM/E;AAgBD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG7E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAmB9E;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;;GAIG;AACH,KAAK,YAAY,GAAG;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;IAClC,QAAQ,EAAE,YAAY,CAAA;CACvB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,YAAY,EAAE,GAAG,SAAS,EACjC,QAAQ,EAAE,MAAM,EAAE,GACjB,gBAAgB,EAAE,CA6FpB"}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Routes-API instruction parsing helpers for the pivot
|
|
3
|
+
* engine.
|
|
4
|
+
*
|
|
5
|
+
* The Routes REST API returns per-step `navigationInstruction.instructions`
|
|
6
|
+
* strings like "Turn left onto Octavia Blvd" that unambiguously name the
|
|
7
|
+
* road being entered. Parsing these is the most reliable way to label a
|
|
8
|
+
* turn — more reliable than `StepInfo.road` from the Android Nav SDK,
|
|
9
|
+
* which lags one step behind for the live currentStep + uses a destination
|
|
10
|
+
* placeholder for the arrival leg.
|
|
11
|
+
*
|
|
12
|
+
* Originally lived in the Navigation miniapp's NavigationPage.tsx; moved
|
|
13
|
+
* into the SDK so every miniapp using `navigation.onPivot()` gets the
|
|
14
|
+
* same accurate road names without having to re-implement the parser.
|
|
15
|
+
*
|
|
16
|
+
* All helpers are pure — no side effects, no shared state.
|
|
17
|
+
*/
|
|
18
|
+
import { bearingDeg, haversineMeters, signedAngleDiff } from "./geometry";
|
|
19
|
+
/**
|
|
20
|
+
* Bare direction words that can sneak through the regex when the
|
|
21
|
+
* instruction's "onto"/"on" clause is followed directly by a bare
|
|
22
|
+
* direction ("Head south on the right"). Reject these so the parser
|
|
23
|
+
* returns null and the caller can hide the label instead of showing
|
|
24
|
+
* "the right" as a road name.
|
|
25
|
+
*/
|
|
26
|
+
const DIRECTION_WORDS = new Set(["right", "left", "the right", "the left", "north", "south", "east", "west"]);
|
|
27
|
+
/**
|
|
28
|
+
* Maneuver verbs that appear in stacked instructions like
|
|
29
|
+
* "Turn left, then turn right onto Linden St" or fragments like
|
|
30
|
+
* "Continue onto Octavia". If a captured "road" contains any of
|
|
31
|
+
* these, it's not a road name — it's leftover instruction syntax
|
|
32
|
+
* from a multi-clause sentence. The parser rejects the capture.
|
|
33
|
+
*/
|
|
34
|
+
const MANEUVER_VERBS = /\b(turn|slight|sharp|continue|head|merge|exit|uturn|u-turn|then|keep)\b/i;
|
|
35
|
+
/**
|
|
36
|
+
* Pull a short road name out of a Routes-API instruction string.
|
|
37
|
+
* Instructions look like:
|
|
38
|
+
* "Turn left onto Octavia Blvd"
|
|
39
|
+
* "Slight right onto Octavia St"
|
|
40
|
+
* "Turn right onto Haight St\nDestination will be on the right"
|
|
41
|
+
*
|
|
42
|
+
* Returns null when the parse fails (e.g. instruction is missing, the
|
|
43
|
+
* "onto" clause is absent, or the captured text contains another
|
|
44
|
+
* maneuver verb / direction word). Callers treat null as "no road
|
|
45
|
+
* name available" and hide the label.
|
|
46
|
+
*
|
|
47
|
+
* Only "onto" is matched here — `\bon\b` was previously used as a
|
|
48
|
+
* fallback for depart steps ("Head north on Market St") but it
|
|
49
|
+
* over-matched, capturing maneuver verbs from stacked instructions
|
|
50
|
+
* ("Turn left, then turn right on..."). The depart step is the
|
|
51
|
+
* very first step and is dropped by the slice(0, -1) loop before
|
|
52
|
+
* this parser is called anyway, so removing the fallback costs us
|
|
53
|
+
* nothing real.
|
|
54
|
+
*/
|
|
55
|
+
export function roadNameFromInstruction(instruction) {
|
|
56
|
+
if (!instruction)
|
|
57
|
+
return null;
|
|
58
|
+
// Only the first line — drop "Destination will be on the right" etc.
|
|
59
|
+
const firstLine = instruction.split("\n")[0] ?? "";
|
|
60
|
+
// Match "onto ROAD" only. The "on" fallback was removed because it
|
|
61
|
+
// matched inside maneuver fragments and captured verbs as fake road
|
|
62
|
+
// names. Real turn instructions always use "onto"; depart steps
|
|
63
|
+
// (the only legitimate "on" users) aren't passed through this path.
|
|
64
|
+
const m = firstLine.match(/\bonto\s+(.+)$/i);
|
|
65
|
+
let raw = (m ? m[1] : "").trim();
|
|
66
|
+
if (!raw)
|
|
67
|
+
return null;
|
|
68
|
+
// A captured road name never contains a comma. If it does, we
|
|
69
|
+
// grabbed the rest of a multi-clause sentence by mistake.
|
|
70
|
+
if (raw.includes(","))
|
|
71
|
+
return null;
|
|
72
|
+
// Cut trailing direction/continuation clauses the API appends.
|
|
73
|
+
raw = raw.split(/\s+(?:toward|towards|to|and|then|for)\b/i)[0]?.trim() ?? "";
|
|
74
|
+
// Strip a unit/suite suffix ("Hayes St #116" → "Hayes St").
|
|
75
|
+
raw = raw.replace(/\s+#.*$/, "").trim();
|
|
76
|
+
if (!raw)
|
|
77
|
+
return null;
|
|
78
|
+
// Reject a bare direction word that slipped through.
|
|
79
|
+
if (DIRECTION_WORDS.has(raw.toLowerCase()))
|
|
80
|
+
return null;
|
|
81
|
+
// Reject anything containing maneuver verbs — the regex caught the
|
|
82
|
+
// wrong clause of a stacked instruction. Real road names don't
|
|
83
|
+
// contain "turn", "slight", "continue", etc.
|
|
84
|
+
if (MANEUVER_VERBS.test(raw))
|
|
85
|
+
return null;
|
|
86
|
+
return raw;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Equality check for road names that's robust to suffix variation
|
|
90
|
+
* ("Gough St" vs "Gough Street"), case, and trailing punctuation.
|
|
91
|
+
* Used to drop "stay on the same road" turns where the routes API
|
|
92
|
+
* names a turn but the user perceives a single continuous street.
|
|
93
|
+
*/
|
|
94
|
+
const ROAD_SUFFIXES = /\b(st|street|ave|avenue|blvd|boulevard|rd|road|dr|drive|ln|lane|way|ct|court|pl|place|ter|terrace|hwy|highway)\b\.?/g;
|
|
95
|
+
function normalizeRoad(road) {
|
|
96
|
+
return road.toLowerCase().replace(ROAD_SUFFIXES, "").replace(/[^a-z0-9 ]/g, "").replace(/\s+/g, " ").trim();
|
|
97
|
+
}
|
|
98
|
+
export function sameRoad(a, b) {
|
|
99
|
+
return normalizeRoad(a) === normalizeRoad(b);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Coarse left/right classifier for a maneuver string. Collapses all
|
|
103
|
+
* left variants (TURN_LEFT, SLIGHT_LEFT, SHARP_LEFT, UTURN_LEFT) to
|
|
104
|
+
* "left" and the rights to "right". Returns null when the maneuver
|
|
105
|
+
* isn't a directional turn (STRAIGHT, NAME_CHANGE, ARRIVE, etc.).
|
|
106
|
+
*/
|
|
107
|
+
export function turnDirection(maneuver) {
|
|
108
|
+
if (!maneuver)
|
|
109
|
+
return null;
|
|
110
|
+
const m = maneuver.toUpperCase();
|
|
111
|
+
if (m.includes("LEFT"))
|
|
112
|
+
return "left";
|
|
113
|
+
if (m.includes("RIGHT"))
|
|
114
|
+
return "right";
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* How sharply the polyline actually bends at a given junction, in
|
|
119
|
+
* degrees [0, 180]. Probe walks outward from the polyline point
|
|
120
|
+
* nearest the junction until ~PROBE_METERS in each direction, then
|
|
121
|
+
* compares incoming vs outgoing bearings. The wide probe (22m) is
|
|
122
|
+
* deliberate: real street corners are rounded over 20–30m and a
|
|
123
|
+
* tighter probe under-reports the angle.
|
|
124
|
+
*
|
|
125
|
+
* Used to drop phantom turns the Routes API names at complex
|
|
126
|
+
* interchanges (Market → Gough → Market) where the drawn polyline is
|
|
127
|
+
* visually one straight line. Returns null when the polyline is too
|
|
128
|
+
* short to measure.
|
|
129
|
+
*/
|
|
130
|
+
const PROBE_METERS = 22;
|
|
131
|
+
export function bendAngleAt(points, junction) {
|
|
132
|
+
const signed = signedBendAt(points, junction);
|
|
133
|
+
return signed == null ? null : Math.abs(signed);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Signed polyline bend at a junction. Positive = right turn, negative
|
|
137
|
+
* = left turn, in [-180, 180]. Used to pick a pivot's left/right
|
|
138
|
+
* direction from geometry when the Routes API's first-step maneuver
|
|
139
|
+
* is misleading (e.g. a curb-alignment micro-jog labeled TURN_LEFT
|
|
140
|
+
* right before the real right turn off Hayes onto Gough).
|
|
141
|
+
*/
|
|
142
|
+
export function signedBendAt(points, junction) {
|
|
143
|
+
if (points.length < 3)
|
|
144
|
+
return null;
|
|
145
|
+
let mid = 0;
|
|
146
|
+
let bestDist = Infinity;
|
|
147
|
+
for (let i = 0; i < points.length; i++) {
|
|
148
|
+
const d = haversineMeters(points[i], junction);
|
|
149
|
+
if (d < bestDist) {
|
|
150
|
+
bestDist = d;
|
|
151
|
+
mid = i;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let before = mid;
|
|
155
|
+
while (before > 0 && haversineMeters(points[before], points[mid]) < PROBE_METERS)
|
|
156
|
+
before--;
|
|
157
|
+
let after = mid;
|
|
158
|
+
while (after < points.length - 1 && haversineMeters(points[after], points[mid]) < PROBE_METERS)
|
|
159
|
+
after++;
|
|
160
|
+
if (before === mid || after === mid)
|
|
161
|
+
return null;
|
|
162
|
+
const incoming = bearingDeg(points[before], points[mid]);
|
|
163
|
+
const outgoing = bearingDeg(points[mid], points[after]);
|
|
164
|
+
return signedAngleDiff(outgoing, incoming);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Minimum bend (degrees) for a junction to count as a real turn worth
|
|
168
|
+
* a pivot. Below this the route is effectively straight through the
|
|
169
|
+
* point; the Routes API may name it as a turn for legal/lane reasons
|
|
170
|
+
* but the user perceives no direction change.
|
|
171
|
+
*/
|
|
172
|
+
export const MIN_TURN_ANGLE_DEG = 30;
|
|
173
|
+
/**
|
|
174
|
+
* Derive accurate turn pivots from a Routes-API step list. Each
|
|
175
|
+
* computed step's `instruction` describes the maneuver that BEGINS
|
|
176
|
+
* that step ("Turn left onto Guerrero St"). A pivot sits at
|
|
177
|
+
* `step[i].end` — the junction where you leave step[i]'s road and
|
|
178
|
+
* turn onto step[i+1]'s road. So for each pair (step[i], step[i+1]):
|
|
179
|
+
*
|
|
180
|
+
* fromRoad = roadNameFromInstruction(step[i].instruction)
|
|
181
|
+
* toRoad = roadNameFromInstruction(step[i+1].instruction)
|
|
182
|
+
* anchor = (step[i].endLat, step[i].endLng)
|
|
183
|
+
* maneuver = step[i+1].maneuver (the actual turn type at the corner)
|
|
184
|
+
*
|
|
185
|
+
* A pivot survives these filters:
|
|
186
|
+
* 1. `fromRoad` parsed successfully from step[i]'s instruction.
|
|
187
|
+
* Drop the pivot otherwise — we don't know the road the user
|
|
188
|
+
* came from, and labeling the dot wouldn't make sense.
|
|
189
|
+
* 2. If `toRoad` parsed too, it must differ from `fromRoad` (drop
|
|
190
|
+
* "stay on same road" jogs). If `toRoad` failed to parse, keep
|
|
191
|
+
* the pivot with `toRoad: null` so the engine can recover it
|
|
192
|
+
* via reverse-geocode. This is what keeps the LAST real turn
|
|
193
|
+
* before arrival in the list — that step's instruction is
|
|
194
|
+
* "Destination will be on the right" with no road name, but
|
|
195
|
+
* the turn itself is real and the user needs to see it.
|
|
196
|
+
* 3. The drawn polyline bends ≥ MIN_TURN_ANGLE_DEG at the junction
|
|
197
|
+
* (drops phantom turns where the geometry is visually straight).
|
|
198
|
+
*
|
|
199
|
+
* The LAST step (the arrival leg itself) is dropped by slice(0, -1) —
|
|
200
|
+
* the destination isn't a turn.
|
|
201
|
+
*
|
|
202
|
+
* Mirrors the Navigation miniapp's preview-turn extraction so live
|
|
203
|
+
* pivots match preview accuracy.
|
|
204
|
+
*/
|
|
205
|
+
export function extractPivotsFromComputedSteps(steps, polyline) {
|
|
206
|
+
if (!steps || steps.length < 2)
|
|
207
|
+
return [];
|
|
208
|
+
const initial = steps.map((s, i) => ({
|
|
209
|
+
stepIdx: i,
|
|
210
|
+
name: s.road ?? roadNameFromInstruction(s.instruction),
|
|
211
|
+
}));
|
|
212
|
+
let annotated = initial;
|
|
213
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
214
|
+
const collapsed = [];
|
|
215
|
+
for (let i = 0; i < annotated.length; i++) {
|
|
216
|
+
const prev = collapsed[collapsed.length - 1];
|
|
217
|
+
const here = annotated[i];
|
|
218
|
+
const next = annotated[i + 1];
|
|
219
|
+
if (prev?.name &&
|
|
220
|
+
next?.name &&
|
|
221
|
+
here.name &&
|
|
222
|
+
!sameRoad(prev.name, here.name) &&
|
|
223
|
+
sameRoad(prev.name, next.name)) {
|
|
224
|
+
// `here` is a sandwiched micro-jog — drop it. `next` will be
|
|
225
|
+
// collapsed against `prev` on the same-road check below.
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
collapsed.push(here);
|
|
229
|
+
}
|
|
230
|
+
if (collapsed.length === annotated.length)
|
|
231
|
+
break;
|
|
232
|
+
annotated = collapsed;
|
|
233
|
+
}
|
|
234
|
+
const out = [];
|
|
235
|
+
// Pair each annotated entry with the next one. Note we no longer
|
|
236
|
+
// walk `steps` directly — `annotated` is the collapsed view, so
|
|
237
|
+
// adjacent annotated entries already represent the real road
|
|
238
|
+
// transitions. `stepIdx` is preserved so we can still look up the
|
|
239
|
+
// junction coordinates and maneuver from the original `steps` array.
|
|
240
|
+
for (let i = 0; i < annotated.length - 1; i++) {
|
|
241
|
+
const here = annotated[i];
|
|
242
|
+
const nextAnn = annotated[i + 1];
|
|
243
|
+
const s = steps[here.stepIdx];
|
|
244
|
+
const next = steps[nextAnn.stepIdx];
|
|
245
|
+
const fromRoad = here.name;
|
|
246
|
+
const toRoad = nextAnn.name;
|
|
247
|
+
// fromRoad is required; toRoad is nullable (last-turn-before-arrival
|
|
248
|
+
// has no road name in the arrival step's instruction).
|
|
249
|
+
if (!fromRoad)
|
|
250
|
+
continue;
|
|
251
|
+
if (toRoad && sameRoad(fromRoad, toRoad))
|
|
252
|
+
continue;
|
|
253
|
+
if (!Number.isFinite(s.endLat) || !Number.isFinite(s.endLng))
|
|
254
|
+
continue;
|
|
255
|
+
const junction = { lat: s.endLat, lng: s.endLng };
|
|
256
|
+
const signedBend = signedBendAt(polyline, junction);
|
|
257
|
+
// No polyline to measure → keep (don't drop a labeled turn just
|
|
258
|
+
// because geometry was unavailable).
|
|
259
|
+
if (signedBend != null && Math.abs(signedBend) < MIN_TURN_ANGLE_DEG)
|
|
260
|
+
continue;
|
|
261
|
+
// Direction precedence: trust polyline geometry first. The Routes
|
|
262
|
+
// API decomposes some junctions into micro-step jogs whose first
|
|
263
|
+
// step's maneuver lies (e.g. a "TURN_LEFT" curb-alignment jog
|
|
264
|
+
// right before the actual right turn off Hayes onto Gough).
|
|
265
|
+
// Geometry doesn't lie. Falls back to the maneuver string when
|
|
266
|
+
// the polyline is too short to measure a bend.
|
|
267
|
+
const geomDir = signedBend == null ? null : signedBend > 0 ? "right" : "left";
|
|
268
|
+
const direction = geomDir ?? turnDirection(next.maneuver);
|
|
269
|
+
out.push({
|
|
270
|
+
lat: s.endLat,
|
|
271
|
+
lng: s.endLng,
|
|
272
|
+
fromRoad,
|
|
273
|
+
toRoad,
|
|
274
|
+
direction,
|
|
275
|
+
maneuver: next.maneuver ?? (direction === "left" ? "TURN_LEFT" : "TURN_RIGHT"),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return out;
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../../src/modules/pivots/instructions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview SpeakerModule — phone-side audio output.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors cloud SDK v3's SpeakerManager naming. Audio *input* (transcription,
|
|
5
|
+
* audio chunks, VAD) lives on session.mic — the split is by I/O direction.
|
|
6
|
+
*
|
|
7
|
+
* Imperative surface:
|
|
8
|
+
* speaker.play({audioUrl}) — play an arbitrary URL via the phone's
|
|
9
|
+
* AudioPlaybackService.
|
|
10
|
+
* speaker.speak(text) — send a SPEAK request. Phone streams cloud
|
|
11
|
+
* TTS when connected and falls back to local
|
|
12
|
+
* offline TTS when cloud is unavailable.
|
|
13
|
+
* Resolves when playback completes; rejects
|
|
14
|
+
* with a TTS_* error code on cloud failure.
|
|
15
|
+
* speaker.createStream(opts) — open a live PCM output stream (16-bit LE).
|
|
16
|
+
* Returns a SpeakerStreamWriter: write() PCM
|
|
17
|
+
* chunks as they arrive (e.g. from a WebSocket
|
|
18
|
+
* in the background), close() to drain, abort()
|
|
19
|
+
* to drop. write() resolves with {bufferedMs}
|
|
20
|
+
* so producers can throttle.
|
|
21
|
+
* speaker.stop() — stop any audio this miniapp is playing.
|
|
22
|
+
*
|
|
23
|
+
* State observability:
|
|
24
|
+
* speaker.state — current SpeakerState (sync getter).
|
|
25
|
+
* speaker.isPlaying — true iff state === "playing".
|
|
26
|
+
* speaker.onStateChange(h) — fires on every state transition.
|
|
27
|
+
*
|
|
28
|
+
* State machine (per miniapp):
|
|
29
|
+
* idle ─── speak()/play() ──► loading ──► playing ──► stopped
|
|
30
|
+
* │ │ │
|
|
31
|
+
* └── error ───┴── stop ───┘
|
|
32
|
+
*
|
|
33
|
+
* `error` is transient — fires once with errorCode set, then settles to
|
|
34
|
+
* `stopped` so isPlaying reads false correctly.
|
|
35
|
+
*/
|
|
36
|
+
import { MiniappSession } from "../session";
|
|
37
|
+
import type { UnsubscribeFn } from "./events";
|
|
38
|
+
export interface PlayAudioOptions {
|
|
39
|
+
audioUrl: string;
|
|
40
|
+
volume?: number;
|
|
41
|
+
stopOtherAudio?: boolean;
|
|
42
|
+
}
|
|
43
|
+
export interface SpeakOptions {
|
|
44
|
+
voice_id?: string;
|
|
45
|
+
voice_settings?: Record<string, unknown>;
|
|
46
|
+
volume?: number;
|
|
47
|
+
stopOtherAudio?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Force this call to use on-device offline TTS, skipping cloud TTS
|
|
50
|
+
* entirely — even when cloud is connected. Rejects with `TTS_LOCAL_UNAVAILABLE`
|
|
51
|
+
* if the offline model isn't ready instead of falling back to cloud.
|
|
52
|
+
*/
|
|
53
|
+
forceLocal?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface SpeakResult {
|
|
56
|
+
/** True if playback completed; false if playback was interrupted. */
|
|
57
|
+
completed: boolean;
|
|
58
|
+
}
|
|
59
|
+
export type SpeakerState = "idle" | "loading" | "playing" | "stopped" | "error";
|
|
60
|
+
/** Sample rates the native chunk player accepts. */
|
|
61
|
+
export type SpeakerStreamSampleRate = 16000 | 24000 | 48000;
|
|
62
|
+
export interface SpeakerStreamOptions {
|
|
63
|
+
/** PCM sample rate in Hz. Default 16000. */
|
|
64
|
+
sampleRate?: SpeakerStreamSampleRate;
|
|
65
|
+
/** Channel count. v1 is mono only. Default 1. */
|
|
66
|
+
channels?: 1;
|
|
67
|
+
/** Playback volume 0..1. Default 1. */
|
|
68
|
+
volume?: number;
|
|
69
|
+
/** Stop any other audio this miniapp is playing first. Default true. */
|
|
70
|
+
stopOtherAudio?: boolean;
|
|
71
|
+
}
|
|
72
|
+
export interface SpeakerStreamWriteResult {
|
|
73
|
+
/** Milliseconds of audio queued host-side but not yet played. */
|
|
74
|
+
bufferedMs: number;
|
|
75
|
+
}
|
|
76
|
+
/** Raw bytes per bridge write. PCM chunks are small; keep messages snappy. */
|
|
77
|
+
export declare const SPEAKER_WRITE_CHUNK_BYTES: number;
|
|
78
|
+
/**
|
|
79
|
+
* Soft backpressure ceiling. When the host reports more than this buffered,
|
|
80
|
+
* it holds the WRITE reply until the buffer drains below it, so a producer
|
|
81
|
+
* that awaits each write self-throttles to realtime.
|
|
82
|
+
*/
|
|
83
|
+
export declare const SPEAKER_STREAM_MAX_BUFFERED_MS = 2000;
|
|
84
|
+
/**
|
|
85
|
+
* Live PCM writer returned by `speaker.createStream()`. 16-bit little-endian
|
|
86
|
+
* PCM only — decode compressed formats (MP3/Opus) server-side before sending.
|
|
87
|
+
*
|
|
88
|
+
* Call `write()` as chunks arrive (each is auto-split into bridge-safe
|
|
89
|
+
* messages), then `close()` to drain and finish, or `abort()` to drop
|
|
90
|
+
* immediately. Shaped like BlobWriter so the two stream APIs feel the same.
|
|
91
|
+
*/
|
|
92
|
+
export declare class SpeakerStreamWriter {
|
|
93
|
+
private readonly session;
|
|
94
|
+
readonly streamId: string;
|
|
95
|
+
private settled;
|
|
96
|
+
private writeChain;
|
|
97
|
+
constructor(session: MiniappSession, streamId: string);
|
|
98
|
+
/**
|
|
99
|
+
* Append raw PCM bytes (16-bit LE). Auto-chunked. Resolves with the host's
|
|
100
|
+
* buffered-ms after the last chunk. The host holds the reply while its
|
|
101
|
+
* buffer is above the backpressure ceiling, so a producer that awaits each
|
|
102
|
+
* write self-throttles to realtime.
|
|
103
|
+
*/
|
|
104
|
+
write(chunk: Uint8Array | ArrayBuffer): Promise<SpeakerStreamWriteResult>;
|
|
105
|
+
/** Append already-base64-encoded PCM bytes (e.g. relayed straight off a WS frame). */
|
|
106
|
+
writeBase64(b64: string): Promise<SpeakerStreamWriteResult>;
|
|
107
|
+
/** Drain the remaining buffer and finish. Resolves when playback has ended. */
|
|
108
|
+
close(): Promise<{
|
|
109
|
+
durationMs?: number;
|
|
110
|
+
}>;
|
|
111
|
+
/** Stop immediately and drop any buffered audio. Idempotent. */
|
|
112
|
+
abort(): Promise<void>;
|
|
113
|
+
private assertOpen;
|
|
114
|
+
private send;
|
|
115
|
+
/** Preserve PCM ordering even when a producer issues overlapping writes. */
|
|
116
|
+
private enqueueWrite;
|
|
117
|
+
}
|
|
118
|
+
export interface SpeakerStateEvent {
|
|
119
|
+
state: SpeakerState;
|
|
120
|
+
/** When state === "error", the underlying error code (TTS_*, INTERNAL). */
|
|
121
|
+
errorCode?: string;
|
|
122
|
+
errorMessage?: string;
|
|
123
|
+
/** When state === "stopped", how many ms the playback ran (best-effort). */
|
|
124
|
+
durationMs?: number;
|
|
125
|
+
}
|
|
126
|
+
export declare class SpeakerModule {
|
|
127
|
+
private readonly session;
|
|
128
|
+
private _state;
|
|
129
|
+
private _lastEvent;
|
|
130
|
+
constructor(session: MiniappSession);
|
|
131
|
+
/** Current speaker playback state. */
|
|
132
|
+
get state(): SpeakerState;
|
|
133
|
+
/** True iff state === "playing". */
|
|
134
|
+
get isPlaying(): boolean;
|
|
135
|
+
/** Play a URL. Resolves when playback completes on the phone. */
|
|
136
|
+
play(options: PlayAudioOptions): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Speak text through the phone. The host streams cloud TTS when connected,
|
|
139
|
+
* then falls back to local offline TTS.
|
|
140
|
+
*
|
|
141
|
+
* Rejects with a MiniappRequestError containing a `code` field on cloud-side
|
|
142
|
+
* TTS failures: `TTS_TEXT_TOO_LONG`, `TTS_INVALID_VOICE`, `TTS_UPSTREAM_ERROR`.
|
|
143
|
+
*/
|
|
144
|
+
speak(text: string, options?: SpeakOptions): Promise<SpeakResult>;
|
|
145
|
+
/**
|
|
146
|
+
* Open a live PCM output stream (16-bit LE) to the phone's audio playback
|
|
147
|
+
* service. Use from the background to play audio that arrives in chunks
|
|
148
|
+
* (e.g. live meeting audio over a WebSocket) with low latency — unlike
|
|
149
|
+
* `play()`, nothing has to be a file or URL first.
|
|
150
|
+
*
|
|
151
|
+
* One stream per miniapp: opening a second closes the first. Rejects with
|
|
152
|
+
* `NOT_IMPLEMENTED` on hosts that predate streaming. Miniapps that depend on
|
|
153
|
+
* this API must declare `minHostVersion: "2.13.0"` or newer.
|
|
154
|
+
*/
|
|
155
|
+
createStream(options?: SpeakerStreamOptions): Promise<SpeakerStreamWriter>;
|
|
156
|
+
/** Stop any audio this miniapp is currently playing. */
|
|
157
|
+
stop(): void;
|
|
158
|
+
/**
|
|
159
|
+
* Subscribe to speaker state transitions. Fires for every change. Does NOT
|
|
160
|
+
* fire immediately with the current value — call `state` separately if you
|
|
161
|
+
* want the seed.
|
|
162
|
+
*/
|
|
163
|
+
onStateChange(handler: (event: SpeakerStateEvent) => void): UnsubscribeFn;
|
|
164
|
+
/** @internal — applied by MiniappSession on inbound SPEAKER_STATE envelope. */
|
|
165
|
+
_applyState(event: SpeakerStateEvent): void;
|
|
166
|
+
/** @internal — for tests. */
|
|
167
|
+
_getLastEvent(): SpeakerStateEvent;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=speaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"speaker.d.ts","sourceRoot":"","sources":["../../src/modules/speaker.ts"],"names":[],"mappings":"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"}
|