@mentra/acs-meeting 3.3.0-dev.515 → 3.3.0-dev.516
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
CHANGED
|
@@ -36,7 +36,7 @@ differences are collected in [iOS](#ios).
|
|
|
36
36
|
**The phone is a relay, not a capture device.** It receives what the glasses already
|
|
37
37
|
encoded, decodes it, and re-publishes it into ACS. Live video is not drawn on the phone,
|
|
38
38
|
and a live frame does not cross the JavaScript bridge. A photo shutter is the exception:
|
|
39
|
-
the phone draws a "Taking a photo" card, then a still, and feeds those pixels through the
|
|
39
|
+
the phone draws a "Taking a photo..." card, then a still, and feeds those pixels through the
|
|
40
40
|
same sender. See [Photo hold](#photo-hold).
|
|
41
41
|
|
|
42
42
|
```
|
|
@@ -542,7 +542,7 @@ publisher (`start_stream` on Direct link; Call's own stream on Cloudflare), keep
|
|
|
542
542
|
meeting, the hotspot, and the ACS sender up, and replaces the tile with three pictures
|
|
543
543
|
in order:
|
|
544
544
|
|
|
545
|
-
1. A full-frame card, "Taking a photo", from the button press until the still is ready.
|
|
545
|
+
1. A full-frame card, "Taking a photo...", from the button press until the still is ready.
|
|
546
546
|
2. The still, for a few seconds counted by the caller from `shownAt`.
|
|
547
547
|
3. Live video again.
|
|
548
548
|
|
|
@@ -139,7 +139,11 @@ class AcsMeetingSession(
|
|
|
139
139
|
private val muted = AtomicBoolean(false)
|
|
140
140
|
private val frameSender = AcsFrameSender(stats, avSync)
|
|
141
141
|
private val outgoingHold = OutgoingVideoHold(
|
|
142
|
-
|
|
142
|
+
// The self-preview mirrors what Teams receives, so it shows the card and the still too.
|
|
143
|
+
send = { planes ->
|
|
144
|
+
DecodedFrameTap.offer(planes)
|
|
145
|
+
frameSender.sendPlanes(planes)
|
|
146
|
+
},
|
|
143
147
|
// The negotiated size, not the profile ceiling: ACS renegotiates below the ceiling under load,
|
|
144
148
|
// and sendPlanes drops any hold frame whose dimensions differ from the negotiated format.
|
|
145
149
|
width = { frameSender.negotiatedSize()?.width ?: profile.width },
|
|
@@ -32,8 +32,8 @@ class OutgoingVideoHold(
|
|
|
32
32
|
private val scheduler = Executors.newSingleThreadScheduledExecutor { runnable ->
|
|
33
33
|
Thread(runnable, "acs-photo-hold").apply { isDaemon = true }
|
|
34
34
|
}
|
|
35
|
-
private var task: ScheduledFuture<*>? = null
|
|
36
|
-
private var planes: HeldPlanes? = null
|
|
35
|
+
@Volatile private var task: ScheduledFuture<*>? = null
|
|
36
|
+
@Volatile private var planes: HeldPlanes? = null
|
|
37
37
|
|
|
38
38
|
fun isActive(): Boolean = running.get()
|
|
39
39
|
|
|
@@ -45,13 +45,17 @@ class OutgoingVideoHold(
|
|
|
45
45
|
* module thread cannot stall (and risk an ANR) waiting for ACS to accept the first frame.
|
|
46
46
|
*/
|
|
47
47
|
fun start(kind: String, imageBytes: ByteArray?, onResult: (Boolean) -> Unit) {
|
|
48
|
-
|
|
48
|
+
// Build the replacement before touching the current hold. Card -> still must not open a gap:
|
|
49
|
+
// while `running` is false the session forwards live glasses frames, and right after a photo
|
|
50
|
+
// those are the reopened camera's unexposed first frames.
|
|
49
51
|
val w = width()
|
|
50
52
|
val h = height()
|
|
51
53
|
val frame = when (kind) {
|
|
52
54
|
"image" -> imageBytes?.let { decode(it, w, h) } ?: card(w, h)
|
|
53
55
|
else -> card(w, h)
|
|
54
56
|
}
|
|
57
|
+
task?.cancel(false)
|
|
58
|
+
task = null
|
|
55
59
|
planes = frame
|
|
56
60
|
running.set(true)
|
|
57
61
|
val settled = AtomicBoolean(false)
|
|
@@ -84,7 +88,7 @@ class OutgoingVideoHold(
|
|
|
84
88
|
textAlign = Paint.Align.CENTER
|
|
85
89
|
textSize = (h / 12f).coerceAtLeast(24f)
|
|
86
90
|
}
|
|
87
|
-
canvas.drawText("Taking a photo", w / 2f, h / 2f, paint)
|
|
91
|
+
canvas.drawText("Taking a photo...", w / 2f, h / 2f, paint)
|
|
88
92
|
return HeldPlanes(bitmap)
|
|
89
93
|
}
|
|
90
94
|
|
|
@@ -189,10 +193,26 @@ private class HeldPlanes(bitmap: Bitmap) {
|
|
|
189
193
|
}
|
|
190
194
|
}
|
|
191
195
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Fresh views per frame: the preview reads a frame on its own worker after the sender has
|
|
198
|
+
* moved on, so frames must not share buffer positions. The pixels never change while held, so
|
|
199
|
+
* retaining one past the callback is safe and needs no bookkeeping.
|
|
200
|
+
*/
|
|
201
|
+
fun frame(): I420Planes = I420Planes(
|
|
202
|
+
y.duplicate().apply { position(0) },
|
|
203
|
+
width,
|
|
204
|
+
u.duplicate().apply { position(0) },
|
|
205
|
+
chromaWidth,
|
|
206
|
+
v.duplicate().apply { position(0) },
|
|
207
|
+
chromaWidth,
|
|
208
|
+
width,
|
|
209
|
+
height,
|
|
210
|
+
System.nanoTime(),
|
|
211
|
+
retain = NO_OP,
|
|
212
|
+
release = NO_OP,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
private companion object {
|
|
216
|
+
val NO_OP: () -> Unit = {}
|
|
197
217
|
}
|
|
198
218
|
}
|
|
@@ -1574,7 +1574,7 @@ func takingPhotoCardPixelBuffer(width: Int, height: Int) -> CVPixelBuffer? {
|
|
|
1574
1574
|
kCTFontAttributeName: font,
|
|
1575
1575
|
kCTForegroundColorAttributeName: CGColor(gray: 1, alpha: 1),
|
|
1576
1576
|
] as CFDictionary
|
|
1577
|
-
guard let attributed = CFAttributedStringCreate(nil, "Taking a photo" as CFString, attrs) else { return nil }
|
|
1577
|
+
guard let attributed = CFAttributedStringCreate(nil, "Taking a photo..." as CFString, attrs) else { return nil }
|
|
1578
1578
|
let line = CTLineCreateWithAttributedString(attributed)
|
|
1579
1579
|
var ascent: CGFloat = 0
|
|
1580
1580
|
let lineWidth = CGFloat(CTLineGetTypographicBounds(line, &ascent, nil, nil))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/acs-meeting",
|
|
3
|
-
"version": "3.3.0-dev.
|
|
3
|
+
"version": "3.3.0-dev.516",
|
|
4
4
|
"description": "MentraOS native ACS Teams meeting module (WHEP decode → ACS raw media)",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@expo/config-plugins": "~55.0.10",
|
|
35
|
-
"@mentra/glasses-media": "3.3.0-dev.
|
|
35
|
+
"@mentra/glasses-media": "3.3.0-dev.516"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"expo-module-scripts": "^55.0.2",
|