autoglm-gui 0.4.7__tar.gz → 0.4.8__tar.gz
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.
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/api/media.py +55 -43
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/scrcpy_stream.py +94 -64
- autoglm_gui-0.4.7/AutoGLM_GUI/static/assets/about-DIdU3ZqP.js → autoglm_gui-0.4.8/AutoGLM_GUI/static/assets/about-BI6OV6gm.js +1 -1
- autoglm_gui-0.4.8/AutoGLM_GUI/static/assets/chat-C_2Cot0q.js +25 -0
- autoglm_gui-0.4.7/AutoGLM_GUI/static/assets/index--ElIPD22.js → autoglm_gui-0.4.8/AutoGLM_GUI/static/assets/index-Dn3vR6uV.js +1 -1
- autoglm_gui-0.4.7/AutoGLM_GUI/static/assets/index-BuFMN8G5.js → autoglm_gui-0.4.8/AutoGLM_GUI/static/assets/index-Do7ha9Kf.js +1 -1
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/static/index.html +1 -1
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/PKG-INFO +1 -1
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/pyproject.toml +1 -1
- autoglm_gui-0.4.7/AutoGLM_GUI/static/assets/chat-_-u1G4Ee.js +0 -25
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/.gitignore +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/__main__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/adb_plus/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/adb_plus/screenshot.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/adb_plus/touch.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/api/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/api/agents.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/api/control.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/api/devices.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/config.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/schemas.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/server.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/state.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/static/assets/index-DCrxTz-A.css +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/AutoGLM_GUI/version.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/LICENSE +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/README.md +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/actions/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/actions/handler.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/adb/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/adb/connection.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/adb/device.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/adb/input.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/adb/screenshot.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/agent.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/config/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/config/apps.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/config/i18n.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/config/prompts.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/config/prompts_en.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/config/prompts_zh.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/model/__init__.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/phone_agent/model/client.py +0 -0
- {autoglm_gui-0.4.7 → autoglm_gui-0.4.8}/scrcpy-server-v3.3.3 +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Media routes: screenshot, video stream, stream reset."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
4
6
|
|
|
5
7
|
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
|
|
6
8
|
|
|
@@ -11,6 +13,9 @@ from AutoGLM_GUI.state import scrcpy_locks, scrcpy_streamers
|
|
|
11
13
|
|
|
12
14
|
router = APIRouter()
|
|
13
15
|
|
|
16
|
+
# Debug configuration: Set DEBUG_SAVE_VIDEO_STREAM=1 to save streams to debug_streams/
|
|
17
|
+
DEBUG_SAVE_STREAM = os.getenv("DEBUG_SAVE_VIDEO_STREAM", "0") == "1"
|
|
18
|
+
|
|
14
19
|
|
|
15
20
|
@router.post("/api/video/reset")
|
|
16
21
|
async def reset_video_stream(device_id: str | None = None) -> dict:
|
|
@@ -81,14 +86,9 @@ async def video_stream_ws(
|
|
|
81
86
|
|
|
82
87
|
print(f"[video/stream] WebSocket connection for device {device_id}")
|
|
83
88
|
|
|
84
|
-
# Debug: Save stream to file for analysis
|
|
85
|
-
# Set to True for debugging (default: False)
|
|
86
|
-
debug_save = False
|
|
89
|
+
# Debug: Save stream to file for analysis (controlled by DEBUG_SAVE_VIDEO_STREAM env var)
|
|
87
90
|
debug_file = None
|
|
88
|
-
if
|
|
89
|
-
import os
|
|
90
|
-
from pathlib import Path
|
|
91
|
-
|
|
91
|
+
if DEBUG_SAVE_STREAM:
|
|
92
92
|
debug_dir = Path("debug_streams")
|
|
93
93
|
debug_dir.mkdir(exist_ok=True)
|
|
94
94
|
debug_file_path = debug_dir / f"{device_id}_{int(__import__('time').time())}.h264"
|
|
@@ -110,46 +110,45 @@ async def video_stream_ws(
|
|
|
110
110
|
await scrcpy_streamers[device_id].start()
|
|
111
111
|
print(f"[video/stream] Scrcpy server started for device {device_id}")
|
|
112
112
|
|
|
113
|
-
# Read
|
|
114
|
-
# Then parse the entire buffer to find complete NAL units
|
|
113
|
+
# Read NAL units until we have SPS, PPS, and IDR
|
|
115
114
|
streamer = scrcpy_streamers[device_id]
|
|
116
|
-
accumulated_buffer = bytearray()
|
|
117
|
-
target_size = 50 * 1024 # Accumulate at least 50KB
|
|
118
115
|
|
|
119
|
-
print(
|
|
120
|
-
for attempt in range(
|
|
116
|
+
print("[video/stream] Reading NAL units for initialization...")
|
|
117
|
+
for attempt in range(20): # Max 20 NAL units for initialization
|
|
121
118
|
try:
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
nal_unit = await streamer.read_nal_unit(auto_cache=True)
|
|
120
|
+
nal_type = nal_unit[4] & 0x1F if len(nal_unit) > 4 else -1
|
|
121
|
+
nal_type_names = {5: "IDR", 7: "SPS", 8: "PPS"}
|
|
125
122
|
print(
|
|
126
|
-
f"[video/stream] Read
|
|
123
|
+
f"[video/stream] Read NAL unit: type={nal_type_names.get(nal_type, nal_type)}, size={len(nal_unit)} bytes"
|
|
127
124
|
)
|
|
125
|
+
|
|
126
|
+
# Check if we have all required parameter sets
|
|
127
|
+
if (
|
|
128
|
+
streamer.cached_sps
|
|
129
|
+
and streamer.cached_pps
|
|
130
|
+
and streamer.cached_idr
|
|
131
|
+
):
|
|
132
|
+
print(
|
|
133
|
+
f"[video/stream] ✓ Initialization complete: SPS={len(streamer.cached_sps)}B, PPS={len(streamer.cached_pps)}B, IDR={len(streamer.cached_idr)}B"
|
|
134
|
+
)
|
|
135
|
+
break
|
|
128
136
|
except Exception as e:
|
|
129
|
-
print(f"[video/stream] Failed to read
|
|
137
|
+
print(f"[video/stream] Failed to read NAL unit: {e}")
|
|
130
138
|
await asyncio.sleep(0.5)
|
|
131
139
|
continue
|
|
132
140
|
|
|
133
|
-
|
|
134
|
-
if len(accumulated_buffer) >= target_size:
|
|
135
|
-
break
|
|
136
|
-
|
|
137
|
-
# Now parse the entire accumulated buffer at once
|
|
138
|
-
# This ensures NAL units spanning multiple chunks are detected as complete
|
|
139
|
-
print(f"[video/stream] Parsing accumulated buffer ({len(accumulated_buffer)} bytes)...")
|
|
140
|
-
streamer._cache_nal_units(bytes(accumulated_buffer))
|
|
141
|
-
|
|
142
|
-
# Get initialization data
|
|
141
|
+
# Get initialization data (SPS + PPS + IDR)
|
|
143
142
|
init_data = streamer.get_initialization_data()
|
|
144
143
|
if not init_data:
|
|
145
144
|
raise RuntimeError(
|
|
146
|
-
|
|
145
|
+
"Failed to get initialization data (missing SPS/PPS/IDR)"
|
|
147
146
|
)
|
|
148
147
|
|
|
149
|
-
# Send initialization data
|
|
148
|
+
# Send initialization data as ONE message (SPS+PPS+IDR combined)
|
|
150
149
|
await websocket.send_bytes(init_data)
|
|
151
150
|
print(
|
|
152
|
-
f"[video/stream] Sent
|
|
151
|
+
f"[video/stream] ✓ Sent initialization data to first client: {len(init_data)} bytes total"
|
|
153
152
|
)
|
|
154
153
|
|
|
155
154
|
# Debug: Save to file
|
|
@@ -188,10 +187,23 @@ async def video_stream_ws(
|
|
|
188
187
|
await asyncio.sleep(0.5)
|
|
189
188
|
|
|
190
189
|
if init_data:
|
|
191
|
-
|
|
190
|
+
# Log what we're sending
|
|
191
|
+
print(
|
|
192
|
+
f"[video/stream] ✓ Sending cached initialization data for device {device_id}:"
|
|
193
|
+
)
|
|
194
|
+
print(
|
|
195
|
+
f" - SPS: {len(streamer.cached_sps) if streamer.cached_sps else 0}B"
|
|
196
|
+
)
|
|
192
197
|
print(
|
|
193
|
-
f"
|
|
198
|
+
f" - PPS: {len(streamer.cached_pps) if streamer.cached_pps else 0}B"
|
|
194
199
|
)
|
|
200
|
+
print(
|
|
201
|
+
f" - IDR: {len(streamer.cached_idr) if streamer.cached_idr else 0}B"
|
|
202
|
+
)
|
|
203
|
+
print(f" - Total: {len(init_data)} bytes")
|
|
204
|
+
|
|
205
|
+
await websocket.send_bytes(init_data)
|
|
206
|
+
print("[video/stream] ✓ Initialization data sent successfully")
|
|
195
207
|
|
|
196
208
|
# Debug: Save to file
|
|
197
209
|
if debug_file:
|
|
@@ -210,23 +222,23 @@ async def video_stream_ws(
|
|
|
210
222
|
|
|
211
223
|
stream_failed = False
|
|
212
224
|
try:
|
|
213
|
-
|
|
225
|
+
nal_count = 0
|
|
214
226
|
while True:
|
|
215
227
|
try:
|
|
216
|
-
#
|
|
217
|
-
#
|
|
218
|
-
|
|
219
|
-
await websocket.send_bytes(
|
|
228
|
+
# Read one complete NAL unit
|
|
229
|
+
# Each WebSocket message = one complete NAL unit (clear semantic boundary)
|
|
230
|
+
nal_unit = await streamer.read_nal_unit(auto_cache=True)
|
|
231
|
+
await websocket.send_bytes(nal_unit)
|
|
220
232
|
|
|
221
233
|
# Debug: Save to file
|
|
222
234
|
if debug_file:
|
|
223
|
-
debug_file.write(
|
|
235
|
+
debug_file.write(nal_unit)
|
|
224
236
|
debug_file.flush()
|
|
225
237
|
|
|
226
|
-
|
|
227
|
-
if
|
|
238
|
+
nal_count += 1
|
|
239
|
+
if nal_count % 100 == 0:
|
|
228
240
|
print(
|
|
229
|
-
f"[video/stream] Device {device_id}: Sent {
|
|
241
|
+
f"[video/stream] Device {device_id}: Sent {nal_count} NAL units"
|
|
230
242
|
)
|
|
231
243
|
except ConnectionError as e:
|
|
232
244
|
print(f"[video/stream] Device {device_id}: Connection error: {e}")
|
|
@@ -260,6 +272,6 @@ async def video_stream_ws(
|
|
|
260
272
|
# Debug: Close file
|
|
261
273
|
if debug_file:
|
|
262
274
|
debug_file.close()
|
|
263
|
-
print(
|
|
275
|
+
print("[video/stream] DEBUG: Closed debug file")
|
|
264
276
|
|
|
265
277
|
print(f"[video/stream] Device {device_id}: Stream ended")
|
|
@@ -47,6 +47,9 @@ class ScrcpyStreamer:
|
|
|
47
47
|
self.sps_pps_locked = False # Lock SPS/PPS after initial complete capture
|
|
48
48
|
# Note: IDR is NOT locked - we keep updating to the latest frame
|
|
49
49
|
|
|
50
|
+
# NAL unit reading buffer (for read_nal_unit method)
|
|
51
|
+
self._nal_read_buffer = bytearray()
|
|
52
|
+
|
|
50
53
|
# Find scrcpy-server location
|
|
51
54
|
self.scrcpy_server_path = self._find_scrcpy_server()
|
|
52
55
|
|
|
@@ -83,6 +86,10 @@ class ScrcpyStreamer:
|
|
|
83
86
|
|
|
84
87
|
async def start(self) -> None:
|
|
85
88
|
"""Start scrcpy server and establish connection."""
|
|
89
|
+
# Clear NAL reading buffer to ensure clean state
|
|
90
|
+
self._nal_read_buffer.clear()
|
|
91
|
+
print("[ScrcpyStreamer] Cleared NAL read buffer")
|
|
92
|
+
|
|
86
93
|
try:
|
|
87
94
|
# 0. Kill existing scrcpy server processes on device
|
|
88
95
|
print("[ScrcpyStreamer] Cleaning up existing scrcpy processes...")
|
|
@@ -407,24 +414,21 @@ class ScrcpyStreamer:
|
|
|
407
414
|
)
|
|
408
415
|
|
|
409
416
|
elif nal_type == 5: # IDR frame
|
|
410
|
-
#
|
|
411
|
-
#
|
|
412
|
-
|
|
417
|
+
# Cache IDR if it's large enough (size check is sufficient)
|
|
418
|
+
# Note: When called from read_nal_unit(), the NAL is guaranteed complete
|
|
419
|
+
# because we extract it between two start codes. The is_complete flag
|
|
420
|
+
# is only False because the NAL is isolated (no next start code in buffer).
|
|
421
|
+
if self.cached_sps and self.cached_pps and size >= 1024:
|
|
413
422
|
is_first = self.cached_idr is None
|
|
414
423
|
self.cached_idr = nal_data
|
|
415
424
|
if is_first:
|
|
416
425
|
print(
|
|
417
|
-
f"[ScrcpyStreamer] ✓ Cached
|
|
426
|
+
f"[ScrcpyStreamer] ✓ Cached IDR frame ({size} bytes)"
|
|
418
427
|
)
|
|
419
428
|
# Don't log every IDR update (too verbose)
|
|
420
|
-
elif not is_complete:
|
|
421
|
-
if size > 1024: # Only log if it's a large incomplete IDR
|
|
422
|
-
print(
|
|
423
|
-
f"[ScrcpyStreamer] ⚠ Skipped INCOMPLETE IDR ({size} bytes, extends to chunk boundary)"
|
|
424
|
-
)
|
|
425
429
|
elif size < 1024:
|
|
426
430
|
print(
|
|
427
|
-
f"[ScrcpyStreamer] ✗ Skipped small IDR ({size} bytes)"
|
|
431
|
+
f"[ScrcpyStreamer] ✗ Skipped small IDR ({size} bytes, likely incomplete)"
|
|
428
432
|
)
|
|
429
433
|
|
|
430
434
|
# Lock SPS/PPS once we have complete initial parameters
|
|
@@ -432,60 +436,6 @@ class ScrcpyStreamer:
|
|
|
432
436
|
self.sps_pps_locked = True
|
|
433
437
|
print("[ScrcpyStreamer] 🔒 SPS/PPS locked (IDR will continue updating)")
|
|
434
438
|
|
|
435
|
-
def _prepend_sps_pps_to_idr(self, data: bytes) -> bytes:
|
|
436
|
-
"""Prepend SPS/PPS before EVERY IDR frame unconditionally.
|
|
437
|
-
|
|
438
|
-
This ensures that clients can start decoding from any IDR frame,
|
|
439
|
-
even if they join mid-stream. We always prepend to guarantee
|
|
440
|
-
that every IDR is self-contained.
|
|
441
|
-
|
|
442
|
-
Returns:
|
|
443
|
-
Modified data with SPS/PPS prepended to all IDR frames
|
|
444
|
-
"""
|
|
445
|
-
if not self.cached_sps or not self.cached_pps:
|
|
446
|
-
return data
|
|
447
|
-
|
|
448
|
-
nal_units = self._find_nal_units(data)
|
|
449
|
-
if not nal_units:
|
|
450
|
-
return data
|
|
451
|
-
|
|
452
|
-
# Find all IDR frames
|
|
453
|
-
idr_positions = [
|
|
454
|
-
(start, size)
|
|
455
|
-
for start, nal_type, size, _ in nal_units
|
|
456
|
-
if nal_type == 5
|
|
457
|
-
]
|
|
458
|
-
|
|
459
|
-
if not idr_positions:
|
|
460
|
-
return data
|
|
461
|
-
|
|
462
|
-
# Build modified data by prepending SPS/PPS before each IDR
|
|
463
|
-
result = bytearray()
|
|
464
|
-
last_pos = 0
|
|
465
|
-
sps_pps = self.cached_sps + self.cached_pps
|
|
466
|
-
|
|
467
|
-
for idr_start, idr_size in idr_positions:
|
|
468
|
-
# Add data before this IDR
|
|
469
|
-
result.extend(data[last_pos:idr_start])
|
|
470
|
-
|
|
471
|
-
# Check if SPS/PPS already exists right before this IDR
|
|
472
|
-
# (to avoid duplicating if scrcpy already sent them)
|
|
473
|
-
prepend_offset = max(0, idr_start - len(sps_pps))
|
|
474
|
-
if data[prepend_offset:idr_start] != sps_pps:
|
|
475
|
-
# Prepend SPS/PPS before this IDR
|
|
476
|
-
result.extend(sps_pps)
|
|
477
|
-
print(
|
|
478
|
-
f"[ScrcpyStreamer] Prepended SPS/PPS before IDR at position {idr_start}"
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
# Update position to start of IDR
|
|
482
|
-
last_pos = idr_start
|
|
483
|
-
|
|
484
|
-
# Add remaining data (including all IDR frames and data after)
|
|
485
|
-
result.extend(data[last_pos:])
|
|
486
|
-
|
|
487
|
-
return bytes(result)
|
|
488
|
-
|
|
489
439
|
def get_initialization_data(self) -> bytes | None:
|
|
490
440
|
"""Get cached SPS/PPS/IDR for initializing new connections.
|
|
491
441
|
|
|
@@ -563,6 +513,86 @@ class ScrcpyStreamer:
|
|
|
563
513
|
)
|
|
564
514
|
raise ConnectionError(f"Failed to read from socket: {e}") from e
|
|
565
515
|
|
|
516
|
+
async def read_nal_unit(self, auto_cache: bool = True) -> bytes:
|
|
517
|
+
"""Read one complete NAL unit from socket.
|
|
518
|
+
|
|
519
|
+
This method ensures each returned chunk is a complete, self-contained NAL unit.
|
|
520
|
+
WebSocket messages will have clear semantic boundaries (one message = one NAL unit).
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
auto_cache: If True, automatically cache SPS/PPS/IDR from this NAL unit
|
|
524
|
+
|
|
525
|
+
Returns:
|
|
526
|
+
bytes: Complete NAL unit (including start code)
|
|
527
|
+
|
|
528
|
+
Raises:
|
|
529
|
+
ConnectionError: If socket is closed or error occurs
|
|
530
|
+
"""
|
|
531
|
+
if not self.tcp_socket:
|
|
532
|
+
raise ConnectionError("Socket not connected")
|
|
533
|
+
|
|
534
|
+
while True:
|
|
535
|
+
# Look for start codes in buffer
|
|
536
|
+
buffer = bytes(self._nal_read_buffer)
|
|
537
|
+
start_positions = []
|
|
538
|
+
|
|
539
|
+
# Find all start codes (0x00 0x00 0x00 0x01 or 0x00 0x00 0x01)
|
|
540
|
+
i = 0
|
|
541
|
+
while i < len(buffer) - 3:
|
|
542
|
+
if buffer[i] == 0x00 and buffer[i + 1] == 0x00:
|
|
543
|
+
if buffer[i + 2] == 0x00 and buffer[i + 3] == 0x01:
|
|
544
|
+
start_positions.append(i)
|
|
545
|
+
i += 4
|
|
546
|
+
elif buffer[i + 2] == 0x01:
|
|
547
|
+
start_positions.append(i)
|
|
548
|
+
i += 3
|
|
549
|
+
else:
|
|
550
|
+
i += 1
|
|
551
|
+
else:
|
|
552
|
+
i += 1
|
|
553
|
+
|
|
554
|
+
# If we have at least 2 start codes, we can extract the first NAL unit
|
|
555
|
+
if len(start_positions) >= 2:
|
|
556
|
+
# Extract first complete NAL unit (from first start code to second start code)
|
|
557
|
+
nal_unit = buffer[start_positions[0] : start_positions[1]]
|
|
558
|
+
|
|
559
|
+
# Remove extracted NAL unit from buffer
|
|
560
|
+
self._nal_read_buffer = bytearray(buffer[start_positions[1] :])
|
|
561
|
+
|
|
562
|
+
# Cache parameter sets if enabled
|
|
563
|
+
if auto_cache:
|
|
564
|
+
self._cache_nal_units(nal_unit)
|
|
565
|
+
|
|
566
|
+
return nal_unit
|
|
567
|
+
|
|
568
|
+
# Need more data - read from socket
|
|
569
|
+
try:
|
|
570
|
+
loop = asyncio.get_event_loop()
|
|
571
|
+
chunk = await loop.run_in_executor(
|
|
572
|
+
None, self.tcp_socket.recv, 512 * 1024
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
if not chunk:
|
|
576
|
+
# Socket closed - return any remaining buffered data as final NAL unit
|
|
577
|
+
if len(self._nal_read_buffer) > 0:
|
|
578
|
+
final_nal = bytes(self._nal_read_buffer)
|
|
579
|
+
self._nal_read_buffer.clear()
|
|
580
|
+
if auto_cache:
|
|
581
|
+
self._cache_nal_units(final_nal)
|
|
582
|
+
return final_nal
|
|
583
|
+
raise ConnectionError("Socket closed by remote")
|
|
584
|
+
|
|
585
|
+
# Append new data to buffer
|
|
586
|
+
self._nal_read_buffer.extend(chunk)
|
|
587
|
+
|
|
588
|
+
except ConnectionError:
|
|
589
|
+
raise
|
|
590
|
+
except Exception as e:
|
|
591
|
+
print(
|
|
592
|
+
f"[ScrcpyStreamer] Unexpected error in read_nal_unit: {type(e).__name__}: {e}"
|
|
593
|
+
)
|
|
594
|
+
raise ConnectionError(f"Failed to read from socket: {e}") from e
|
|
595
|
+
|
|
566
596
|
def stop(self) -> None:
|
|
567
597
|
"""Stop scrcpy server and cleanup resources."""
|
|
568
598
|
# Close socket
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as o}from"./index
|
|
1
|
+
import{j as o}from"./index-Dn3vR6uV.js";function t(){return o.jsx("div",{className:"p-2",children:o.jsx("h3",{children:"About"})})}export{t as component};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import{j as l,r as x,g as Ie,a as Oe,s as Ue,b as Ne,c as $e,d as Te,e as He,f as ze,i as Ye,h as Ve,k as We,l as Xe}from"./index-Dn3vR6uV.js";function Ge({id:m,model:ce,status:U,isInitialized:R,isActive:k,onClick:O}){const $=U==="device";return l.jsx("button",{onClick:O,className:`w-full text-left px-4 py-3 rounded-lg transition-all duration-500 ease-[cubic-bezier(0.4,0.0,0.2,1)] h-12 shrink-0 ${k?"bg-blue-500 text-white shadow-md":"bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700"}`,children:l.jsxs("div",{className:"flex items-center justify-between gap-2",children:[l.jsxs("div",{className:"flex items-center gap-3 min-w-0 flex-1",children:[l.jsx("div",{className:`w-2.5 h-2.5 rounded-full flex-shrink-0 ${$?"bg-green-400 shadow-[0_0_4px_rgba(74,222,128,0.6)]":"bg-gray-400"}`,title:$?"在线":"离线"}),l.jsxs("div",{className:"min-w-0 flex-1",children:[l.jsx("div",{className:`font-medium text-sm truncate ${k?"text-white":"text-gray-900 dark:text-gray-100"}`,children:ce||"未知设备"}),l.jsx("div",{className:`text-xs truncate ${k?"text-blue-100":"text-gray-500 dark:text-gray-400"}`,children:m})]})]}),R&&l.jsx("div",{className:`flex-shrink-0 w-5 h-5 rounded-full flex items-center justify-center ${k?"bg-white/20":"bg-green-100 dark:bg-green-900"}`,children:l.jsx("svg",{className:`w-3 h-3 ${k?"text-white":"text-green-600 dark:text-green-400"}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M5 13l4 4L19 7"})})})]})})}const Ke=()=>{try{const m=localStorage.getItem("sidebar-collapsed");return m!==null?JSON.parse(m):!1}catch(m){return console.warn("Failed to load sidebar collapsed state:",m),!1}};function Je({devices:m,currentDeviceId:ce,onSelectDevice:U,onOpenConfig:R}){const[k,O]=x.useState(Ke);x.useEffect(()=>{localStorage.setItem("sidebar-collapsed",JSON.stringify(k))},[k]),x.useEffect(()=>{const w=C=>{(C.metaKey||C.ctrlKey)&&C.key==="b"&&(C.preventDefault(),O(!k))};return window.addEventListener("keydown",w),()=>window.removeEventListener("keydown",w)},[k]);const $=()=>{O(!k)};return l.jsxs(l.Fragment,{children:[k&&l.jsx("button",{onClick:$,className:"fixed left-0 top-20 w-8 h-16 bg-blue-500 hover:bg-blue-600 text-white rounded-r-full shadow-lg transition-all duration-300 z-50 flex items-center justify-center",title:"展开侧边栏",children:l.jsx("svg",{className:"w-4 h-4 transition-transform duration-300",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M9 5l7 7-7 7"})})}),l.jsxs("div",{className:`${k?"w-0 -ml-8":"w-64"} transition-all duration-500 ease-[cubic-bezier(0.4,0.0,0.2,1)] h-full min-h-0 bg-gray-50 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-700 flex flex-col overflow-hidden`,children:[l.jsxs("div",{className:"border-b border-gray-200 dark:border-gray-700 flex items-center justify-between p-4 whitespace-nowrap",children:[l.jsxs("div",{children:[l.jsxs("h2",{className:"text-lg font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2",children:[l.jsx("svg",{className:"w-5 h-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"})}),"设备列表"]}),l.jsxs("p",{className:"text-xs text-gray-500 dark:text-gray-400 mt-1",children:["共 ",m.length," 个设备"]})]}),l.jsx("button",{onClick:$,className:"p-1.5 hover:bg-gray-200 dark:hover:bg-gray-700 rounded transition-all duration-300 ease-[cubic-bezier(0.4,0.0,0.2,1)]",title:"收缩侧边栏",children:l.jsx("svg",{className:"w-4 h-4 text-gray-500 dark:text-gray-400 transition-transform duration-500 ease-[cubic-bezier(0.4,0.0,0.2,1)]",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M15 19l-7-7 7-7"})})})]}),l.jsx("div",{className:"flex-1 overflow-y-auto p-3 space-y-2 min-h-0",children:m.length===0?l.jsxs("div",{className:"text-center py-8 text-gray-500 dark:text-gray-400",children:[l.jsx("svg",{className:"w-12 h-12 mx-auto mb-2 opacity-50",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"})}),l.jsx("p",{className:"text-sm",children:"未检测到设备"}),l.jsx("p",{className:"text-xs mt-1",children:"请连接 ADB 设备"})]}):m.map(w=>l.jsx(Ge,{id:w.id,model:w.model,status:w.status,isInitialized:w.is_initialized,isActive:w.id===ce,onClick:()=>U(w.id)},w.id))}),l.jsx("div",{className:"p-3 border-t border-gray-200 dark:border-gray-700 space-y-2 whitespace-nowrap",children:l.jsxs("button",{onClick:R,className:"w-full px-4 py-2 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded-lg transition-all duration-500 ease-[cubic-bezier(0.4,0.0,0.2,1)] font-medium text-gray-700 dark:text-gray-300 flex items-center justify-center gap-2",children:[l.jsxs("svg",{className:"w-4 h-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:[l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"}),l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M15 12a3 3 0 11-6 0 3 3 0 016 0z"})]}),"全局配置"]})})]})]})}var Fe={exports:{}};const qe={},Ze=Object.freeze(Object.defineProperty({__proto__:null,default:qe},Symbol.toStringTag,{value:"Module"})),Qe=Ie(Ze);var et=Fe.exports,_e;function tt(){return _e||(_e=1,(function(m,ce){(function(U,R){m.exports=R(Qe)})(et,(function(U){function R(r,a){(a==null||a>r.length)&&(a=r.length);for(var e=0,t=Array(a);e<a;e++)t[e]=r[e];return t}function k(r){if(Array.isArray(r))return r}function O(r){if(Array.isArray(r))return R(r)}function $(r){if(r===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return r}function w(r,a){if(!(r instanceof a))throw new TypeError("Cannot call a class as a function")}function C(r,a){for(var e=0;e<a.length;e++){var t=a[e];t.enumerable=t.enumerable||!1,t.configurable=!0,"value"in t&&(t.writable=!0),Object.defineProperty(r,X(t.key),t)}}function T(r,a,e){return a&&C(r.prototype,a),e&&C(r,e),Object.defineProperty(r,"prototype",{writable:!1}),r}function p(r,a){var e=typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(!e){if(Array.isArray(r)||(e=Y(r))||a){e&&(r=e);var t=0,n=function(){};return{s:n,n:function(){return t>=r.length?{done:!0}:{done:!1,value:r[t++]}},e:function(c){throw c},f:n}}throw new TypeError(`Invalid attempt to iterate non-iterable instance.
|
|
2
|
+
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}var i,s=!0,o=!1;return{s:function(){e=e.call(r)},n:function(){var c=e.next();return s=c.done,c},e:function(c){o=!0,i=c},f:function(){try{s||e.return==null||e.return()}finally{if(o)throw i}}}}function A(r){var a=te();return function(){var e,t=E(r);if(a){var n=E(this).constructor;e=Reflect.construct(t,arguments,n)}else e=t.apply(this,arguments);return ge(this,e)}}function D(r,a,e){return(a=X(a))in r?Object.defineProperty(r,a,{value:e,enumerable:!0,configurable:!0,writable:!0}):r[a]=e,r}function E(r){return E=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(a){return a.__proto__||Object.getPrototypeOf(a)},E(r)}function V(r,a){if(typeof a!="function"&&a!==null)throw new TypeError("Super expression must either be null or a function");r.prototype=Object.create(a&&a.prototype,{constructor:{value:r,writable:!0,configurable:!0}}),Object.defineProperty(r,"prototype",{writable:!1}),a&&de(r,a)}function te(){try{var r=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch{}return(te=function(){return!!r})()}function ve(r){if(typeof Symbol<"u"&&r[Symbol.iterator]!=null||r["@@iterator"]!=null)return Array.from(r)}function re(r,a){var e=r==null?null:typeof Symbol<"u"&&r[Symbol.iterator]||r["@@iterator"];if(e!=null){var t,n,i,s,o=[],c=!0,u=!1;try{if(i=(e=e.call(r)).next,a!==0)for(;!(c=(t=i.call(e)).done)&&(o.push(t.value),o.length!==a);c=!0);}catch(d){u=!0,n=d}finally{try{if(!c&&e.return!=null&&(s=e.return(),Object(s)!==s))return}finally{if(u)throw n}}return o}}function ae(){throw new TypeError(`Invalid attempt to destructure non-iterable instance.
|
|
3
|
+
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function H(){throw new TypeError(`Invalid attempt to spread non-iterable instance.
|
|
4
|
+
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function ge(r,a){if(a&&(typeof a=="object"||typeof a=="function"))return a;if(a!==void 0)throw new TypeError("Derived constructors may only return object or undefined");return $(r)}function de(r,a){return de=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},de(r,a)}function z(r,a){return k(r)||re(r,a)||Y(r,a)||ae()}function j(r){return O(r)||ve(r)||Y(r)||H()}function Q(r,a){if(typeof r!="object"||!r)return r;var e=r[Symbol.toPrimitive];if(e!==void 0){var t=e.call(r,a);if(typeof t!="object")return t;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(r)}function X(r){var a=Q(r,"string");return typeof a=="symbol"?a:a+""}function ne(r){"@babel/helpers - typeof";return ne=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(a){return typeof a}:function(a){return a&&typeof Symbol=="function"&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},ne(r)}function Y(r,a){if(r){if(typeof r=="string")return R(r,a);var e={}.toString.call(r).slice(8,-1);return e==="Object"&&r.constructor&&(e=r.constructor.name),e==="Map"||e==="Set"?Array.from(r):e==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?R(r,a):void 0}}var ie,ee;function q(r,a){ie=r,ee=a}function b(r){if(ie){for(var a=arguments.length,e=new Array(a>1?a-1:0),t=1;t<a;t++)e[t-1]=arguments[t];ie.apply(void 0,[r].concat(e))}}function K(r){if(ee){for(var a=arguments.length,e=new Array(a>1?a-1:0),t=1;t<a;t++)e[t-1]=arguments[t];ee.apply(void 0,[r].concat(e))}}var le=(function(){function r(a){w(this,r),this.listener={},this.type=a|""}return T(r,[{key:"on",value:function(e,t){return this.listener[e]||(this.listener[e]=[]),this.listener[e].push(t),!0}},{key:"off",value:function(e,t){if(this.listener[e]){var n=this.listener[e].indexOf(t);return n>-1&&this.listener[e].splice(n,1),!0}return!1}},{key:"offAll",value:function(){this.listener={}}},{key:"dispatch",value:function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i<t;i++)n[i-1]=arguments[i];return this.listener[e]?(this.listener[e].map(function(s){s.apply(null,n)}),!0):!1}}]),r})(),fe=(function(){function r(){w(this,r)}return T(r,null,[{key:"init",value:function(){r.types={avc1:[],avcC:[],btrt:[],dinf:[],dref:[],esds:[],ftyp:[],hdlr:[],hev1:[],hvcC:[],mdat:[],mdhd:[],mdia:[],mfhd:[],minf:[],moof:[],moov:[],mp4a:[],mvex:[],mvhd:[],sdtp:[],stbl:[],stco:[],stsc:[],stsd:[],stsz:[],stts:[],tfdt:[],tfhd:[],traf:[],trak:[],trun:[],trex:[],tkhd:[],vmhd:[],smhd:[]};var e;for(e in r.types)r.types.hasOwnProperty(e)&&(r.types[e]=[e.charCodeAt(0),e.charCodeAt(1),e.charCodeAt(2),e.charCodeAt(3)]);var t=new Uint8Array([0,0,0,0,0,0,0,0,118,105,100,101,0,0,0,0,0,0,0,0,0,0,0,0,86,105,100,101,111,72,97,110,100,108,101,114,0]),n=new Uint8Array([0,0,0,0,0,0,0,0,115,111,117,110,0,0,0,0,0,0,0,0,0,0,0,0,83,111,117,110,100,72,97,110,100,108,101,114,0]);r.HDLR_TYPES={video:t,audio:n};var i=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,12,117,114,108,32,0,0,0,1]),s=new Uint8Array([0,0,0,0,0,0,0,0]);r.STTS=r.STSC=r.STCO=s,r.STSZ=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0]),r.VMHD=new Uint8Array([0,0,0,1,0,0,0,0,0,0,0,0]),r.SMHD=new Uint8Array([0,0,0,0,0,0,0,0]),r.STSD=new Uint8Array([0,0,0,0,0,0,0,1]);var o=new Uint8Array([105,115,111,109]),c=new Uint8Array([97,118,99,49]),u=new Uint8Array([0,0,0,1]);r.FTYP=r.box(r.types.ftyp,o,u,o,c),r.DINF=r.box(r.types.dinf,r.box(r.types.dref,i))}},{key:"box",value:function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i<t;i++)n[i-1]=arguments[i];for(var s=8,o=n.length,c=o,u;o--;)s+=n[o].byteLength;for(u=new Uint8Array(s),u[0]=s>>24&255,u[1]=s>>16&255,u[2]=s>>8&255,u[3]=s&255,u.set(e,4),o=0,s=8;o<c;++o)u.set(n[o],s),s+=n[o].byteLength;return u}},{key:"hdlr",value:function(e){return r.box(r.types.hdlr,r.HDLR_TYPES[e])}},{key:"mdat",value:function(e){return r.box(r.types.mdat,e)}},{key:"mdhd",value:function(e,t){return r.box(r.types.mdhd,new Uint8Array([0,0,0,0,0,0,0,2,0,0,0,3,e>>24&255,e>>16&255,e>>8&255,e&255,t>>>24&255,t>>>16&255,t>>>8&255,t&255,85,196,0,0]))}},{key:"mdia",value:function(e){return r.box(r.types.mdia,r.mdhd(e.timescale,e.duration),r.hdlr(e.type),r.minf(e))}},{key:"mfhd",value:function(e){return r.box(r.types.mfhd,new Uint8Array([0,0,0,0,e>>24,e>>16&255,e>>8&255,e&255]))}},{key:"minf",value:function(e){return e.type==="audio"?r.box(r.types.minf,r.box(r.types.smhd,r.SMHD),r.DINF,r.stbl(e)):r.box(r.types.minf,r.box(r.types.vmhd,r.VMHD),r.DINF,r.stbl(e))}},{key:"moof",value:function(e,t,n){return r.box(r.types.moof,r.mfhd(e),r.traf(n,t))}},{key:"moov",value:function(e,t,n){for(var i=e.length,s=[];i--;)s[i]=r.trak(e[i]);return r.box.apply(null,[r.types.moov,r.mvhd(n,t)].concat(s).concat(r.mvex(e)))}},{key:"mvex",value:function(e){for(var t=e.length,n=[];t--;)n[t]=r.trex(e[t]);return r.box.apply(null,[r.types.mvex].concat(n))}},{key:"mvhd",value:function(e,t){var n=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,2,e>>24&255,e>>16&255,e>>8&255,e&255,t>>>24&255,t>>>16&255,t>>>8&255,t&255,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return r.box(r.types.mvhd,n)}},{key:"sdtp",value:function(e){var t=e.samples||[],n=new Uint8Array(4+t.length),i,s;for(s=0;s<t.length;s++)i=t[s].flags,n[s+4]=i.dependsOn<<4|i.isDependedOn<<2|i.hasRedundancy;return r.box(r.types.sdtp,n)}},{key:"stbl",value:function(e){return r.box(r.types.stbl,r.stsd(e),r.box(r.types.stts,r.STTS),r.box(r.types.stsc,r.STSC),r.box(r.types.stsz,r.STSZ),r.box(r.types.stco,r.STCO))}},{key:"avc1",value:function(e){var t=[],n=[],i,s,o;for(i=0;i<e.sps.length;i++)s=e.sps[i],o=s.byteLength,t.push(o>>>8&255),t.push(o&255),t=t.concat(Array.prototype.slice.call(s));for(i=0;i<e.pps.length;i++)s=e.pps[i],o=s.byteLength,n.push(o>>>8&255),n.push(o&255),n=n.concat(Array.prototype.slice.call(s));var c=r.box(r.types.avcC,new Uint8Array([1,t[3],t[4],t[5],255,224|e.sps.length].concat(t).concat([e.pps.length]).concat(n))),u=e.width,d=e.height;return r.box(r.types.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,u>>8&255,u&255,d>>8&255,d&255,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,98,105,110,101,108,112,114,111,46,114,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),c,r.box(r.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])))}},{key:"hev1",value:function(e){for(var t=[],n=[],i=[],s,o,c=0;c<(((u=e.vps)===null||u===void 0?void 0:u.length)||0);c++){var u;s=e.vps[c],o=s.byteLength,t.push(o>>>8&255,o&255),t=t.concat(Array.prototype.slice.call(s))}for(var d=0;d<(((f=e.sps)===null||f===void 0?void 0:f.length)||0);d++){var f;s=e.sps[d],o=s.byteLength,n.push(o>>>8&255,o&255),n=n.concat(Array.prototype.slice.call(s))}for(var h=0;h<(((y=e.pps)===null||y===void 0?void 0:y.length)||0);h++){var y;s=e.pps[h],o=s.byteLength,i.push(o>>>8&255,o&255),i=i.concat(Array.prototype.slice.call(s))}var S=e.hvcC,B=S.profile_space,M=S.tier_flag,_=S.profile_idc,I=S.profile_compatibility_flags,P=S.constraint_indicator_flags,pe=S.level_idc,Z=S.chroma_format_idc,ye=r.box(r.types.hvcC,new Uint8Array([1,B<<6|M<<5|_,I>>24&255,I>>16&255,I>>8&255,I&255].concat(j(P),[pe,240,0,252,252|Z,248,248,0,0,3,3,32,0,1],j(t),[33,0,1],j(n),[34,0,1],j(i)))),ue=e.width,F=e.height;return r.box(r.types.hev1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,ue>>8&255,ue&255,F>>8&255,F&255,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,98,105,110,101,108,112,114,111,46,114,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),ye,r.box(r.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])))}},{key:"esds",value:function(e){var t=e.config.byteLength,n=new Uint8Array(26+t+3);return n.set([0,0,0,0,3,23+t,0,1,0,4,15+t,64,21,0,0,0,0,0,0,0,0,0,0,0,5,t]),n.set(e.config,26),n.set([6,1,2],26+t),n}},{key:"mp4a",value:function(e){var t=e.audiosamplerate;return r.box(r.types.mp4a,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,e.channelCount,0,16,0,0,0,0,t>>8&255,t&255,0,0]),r.box(r.types.esds,r.esds(e)))}},{key:"stsd",value:function(e){return e.type==="audio"?r.box(r.types.stsd,r.STSD,r.mp4a(e)):e.codec.startsWith("hvc1")?r.box(r.types.stsd,r.STSD,r.hev1(e)):r.box(r.types.stsd,r.STSD,r.avc1(e))}},{key:"tkhd",value:function(e){var t=e.id,n=e.duration,i=e.width,s=e.height,o=e.volume;return r.box(r.types.tkhd,new Uint8Array([0,0,0,7,0,0,0,0,0,0,0,0,t>>24&255,t>>16&255,t>>8&255,t&255,0,0,0,0,n>>>24&255,n>>>16&255,n>>>8&255,n&255,0,0,0,0,0,0,0,0,0,0,0,0,o>>0&255,o%1*10>>0&255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,i>>8&255,i&255,0,0,s>>8&255,s&255,0,0]))}},{key:"traf",value:function(e,t){var n=r.sdtp(e),i=e.id;return r.box(r.types.traf,r.box(r.types.tfhd,new Uint8Array([0,0,0,0,i>>24,i>>16&255,i>>8&255,i&255])),r.box(r.types.tfdt,new Uint8Array([0,0,0,0,t>>24,t>>16&255,t>>8&255,t&255])),r.trun(e,n.length+16+16+8+16+8+8),n)}},{key:"trak",value:function(e){return e.duration=e.duration||4294967295,r.box(r.types.trak,r.tkhd(e),r.mdia(e))}},{key:"trex",value:function(e){var t=e.id;return r.box(r.types.trex,new Uint8Array([0,0,0,0,t>>24,t>>16&255,t>>8&255,t&255,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]))}},{key:"trun",value:function(e,t){var n=e.samples||[],i=n.length,s=12+16*i,o=new Uint8Array(s),c,u,d,f,h,y;for(t+=8+s,o.set([0,0,15,1,i>>>24&255,i>>>16&255,i>>>8&255,i&255,t>>>24&255,t>>>16&255,t>>>8&255,t&255],0),c=0;c<i;c++)u=n[c],d=u.duration,f=u.size,h=u.flags,y=u.cts,o.set([d>>>24&255,d>>>16&255,d>>>8&255,d&255,f>>>24&255,f>>>16&255,f>>>8&255,f&255,h.isLeading<<2|h.dependsOn,h.isDependedOn<<6|h.hasRedundancy<<4|h.paddingValue<<1|h.isNonSync,h.degradPrio&61440,h.degradPrio&15,y>>>24&255,y>>>16&255,y>>>8&255,y&255],12+16*c);return r.box(r.types.trun,o)}},{key:"initSegment",value:function(e,t,n){r.types||r.init();var i=r.moov(e,t,n),s;return s=new Uint8Array(r.FTYP.byteLength+i.byteLength),s.set(r.FTYP),s.set(i,r.FTYP.byteLength),s}}]),r})(),ke=(function(){function r(){w(this,r)}return T(r,null,[{key:"samplingRateMap",get:function(){return[96e3,88200,64e3,48e3,44100,32e3,24e3,22050,16e3,12e3,11025,8e3,7350]}},{key:"getHeaderLength",value:function(e){return e[1]&1?7:9}},{key:"getFrameLength",value:function(e){return(e[3]&3)<<11|e[4]<<3|(e[5]&224)>>>5}},{key:"isAACPattern",value:function(e){return e[0]===255&&(e[1]&240)===240&&(e[1]&6)===0}},{key:"extractAAC",value:function(e){var t=0,n=e.byteLength,i=[],s,o;if(!r.isAACPattern(e))return K("Invalid ADTS audio format"),{valid:!1};s=r.getHeaderLength(e);for(var c=e.subarray(0,s);t<n;)o=r.getFrameLength(e),i.push(e.subarray(s,o)),e=e.slice(o),t+=o;return{valid:!0,header:c,slices:i}}}]),r})(),be=1,g=(function(r){V(e,r);var a=A(e);function e(){return w(this,e),a.apply(this,arguments)}return T(e,[{key:"flush",value:function(){this.mp4track.len=0,this.mp4track.samples=[]}},{key:"isReady",value:function(){return!this.readyToDecode||!this.samples.length?null:!0}}],[{key:"getTrackID",value:function(){return be++}}]),e})(le),J=(function(r){V(e,r);var a=A(e);function e(t,n,i){var s;return w(this,e),s=a.call(this,"AACRemuxer"),s.frameDuration=i,s.readyToDecode=!1,s.header=null,s.nextDts=0,s.dts=0,s.mp4track={id:g.getTrackID(),type:"audio",channelCount:0,len:0,fragmented:!0,timescale:t,duration:n,samples:[],config:"",codec:""},s.samples=[],s}return T(e,[{key:"resetTrack",value:function(){this.readyToDecode=!1,this.header=null,this.mp4track.codec="",this.mp4track.channelCount="",this.mp4track.config="",this.mp4track.timescale=this.timescale,this.nextDts=0,this.dts=0}},{key:"feed",value:function(n,i){var s=ke.extractAAC(n),o=s.valid,c=s.header,u=s.slices;return this.header||(this.header=c),o&&u.length>0?(this.remux(this.getAudioFrames(u,i)),!0):(K("Failed to extract audio data from:",n),this.dispatch("outOfData"),!1)}},{key:"getAudioFrames",value:function(n,i){var s=[],o=0,c=0,u=p(n),d;try{for(u.s();!(d=u.n()).done;){var f=d.value;s.push({units:f})}}catch(h){u.e(h)}finally{u.f()}return o=i?i/s.length|0:this.frameDuration,c=i?i-o*s.length:0,s.map(function(h){h.duration=o,c>0&&(h.duration++,c--)}),s}},{key:"remux",value:function(n){if(n.length>0)for(var i=0;i<n.length;i++){var s=n[i],o=s.units,c=o.byteLength;this.samples.push({units:o,size:c,duration:s.duration}),this.mp4track.len+=c,this.readyToDecode||this.setAACConfig()}}},{key:"getPayload",value:function(){if(!this.isReady())return null;var n=new Uint8Array(this.mp4track.len),i=0,s=this.mp4track.samples,o,c;for(this.dts=this.nextDts;this.samples.length;){var u=this.samples.shift();if(u.units,c=u.duration,c<=0){b("remuxer: invalid sample duration at DTS: ".concat(this.nextDts," :").concat(c)),this.mp4track.len-=u.size;continue}this.nextDts+=c,o={size:u.size,duration:c,cts:0,flags:{isLeading:0,isDependedOn:0,hasRedundancy:0,degradPrio:0,dependsOn:1}},n.set(u.units,i),i+=u.size,s.push(o)}return s.length?new Uint8Array(n.buffer,0,this.mp4track.len):null}},{key:"setAACConfig",value:function(){var n,i,s,o=new Uint8Array(2);this.header&&(n=((this.header[2]&192)>>>6)+1,i=(this.header[2]&60)>>>2,s=(this.header[2]&1)<<2,s|=(this.header[3]&192)>>>6,o[0]=n<<3,o[0]|=(i&14)>>1,o[1]|=(i&1)<<7,o[1]|=s<<3,this.mp4track.codec="mp4a.40."+n,this.mp4track.channelCount=s,this.mp4track.config=o,this.readyToDecode=!0)}}]),e})(g),W=(function(){function r(a){w(this,r),this.data=a,this.index=0,this.bitLength=a.byteLength*8}return T(r,[{key:"setData",value:function(e){this.data=e,this.index=0,this.bitLength=e.byteLength*8}},{key:"bitsAvailable",get:function(){return this.bitLength-this.index}},{key:"skipBits",value:function(e){if(this.bitsAvailable<e)return!1;this.index+=e}},{key:"readBits",value:function(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,n=this.getBits(e,this.index,t);return n}},{key:"getBits",value:function(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!0;if(this.bitsAvailable<e)return 0;var i=t%8,s=this.data[t/8|0]&255>>>i,o=8-i;if(o>=e)return n&&(this.index+=e),s>>o-e;n&&(this.index+=o);var c=e-o;return s<<c|this.getBits(c,t+o,n)}},{key:"skipLZ",value:function(){var e;for(e=0;e<this.bitLength-this.index;++e)if(this.getBits(1,this.index+e,!1)!==0)return this.index+=e,e;return e}},{key:"skipUEG",value:function(){this.skipBits(1+this.skipLZ())}},{key:"skipEG",value:function(){this.skipBits(1+this.skipLZ())}},{key:"readUEG",value:function(){var e=this.skipLZ();return this.readBits(e+1)-1}},{key:"readEG",value:function(){var e=this.readUEG();return 1&e?1+e>>>1:-1*(e>>>1)}},{key:"readBoolean",value:function(){return this.readBits(1)===1}},{key:"readUByte",value:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:1;return this.readBits(e*8)}},{key:"readUShort",value:function(){return this.readBits(16)}},{key:"readUInt",value:function(){return this.readBits(32)}}]),r})(),se=(function(){function r(){w(this,r)}return T(r,null,[{key:"extractNALu",value:function(e){for(var t=0,n=e.byteLength,i=[],s=0,o=0;t<n;){var c=e[t++];if(c===0)o++;else if(c===1&&o>=2){var u=o+1;s!==t-u&&i.push(e.subarray(s,t-u)),s=t,o=0}else o=0}var d=null;return s<n&&(d=e.subarray(s,n)),[i,d]}},{key:"skipScalingList",value:function(e,t){for(var n=8,i=8,s,o=0;o<t;o++)i!==0&&(s=e.readEG(),i=(n+s+256)%256),n=i===0?n:i}},{key:"readSPS",value:function(e){var t=new W(e),n=0,i=0,s=0,o=0,c=1,u,d,f,h,y,S,B=0;t.readUByte();for(var M=[],_=1,I=e.byteLength,P=_;P<I;P++)P+2<I&&t.readBits(24,!1)===3?(M.push(t.readBits(8)),M.push(t.readBits(8)),P+=2,t.readBits(8)):M.push(t.readBits(8));if(t.setData(new Uint8Array(M)),u=t.readUByte(),t.readBits(5),t.skipBits(3),t.readUByte(),t.skipUEG(),u===100||u===110||u===122||u===244||u===44||u===83||u===86||u===118||u===128){var pe=t.readUEG();if(pe===3&&t.skipBits(1),t.skipUEG(),t.skipUEG(),t.skipBits(1),t.readBoolean()){S=pe!==3?8:12;for(var Z=0;Z<S;++Z)t.readBoolean()&&(Z<6?r.skipScalingList(t,16):r.skipScalingList(t,64))}}t.skipUEG();var ye=t.readUEG();if(ye===0)t.readUEG();else if(ye===1){t.skipBits(1),t.skipEG(),t.skipEG(),d=t.readUEG();for(var ue=0;ue<d;++ue)t.skipEG()}if(t.skipUEG(),t.skipBits(1),f=t.readUEG(),h=t.readUEG(),y=t.readBits(1),y===0&&t.skipBits(1),t.skipBits(1),t.readBoolean()&&(n=t.readUEG(),i=t.readUEG(),s=t.readUEG(),o=t.readUEG()),t.readBoolean()){if(t.readBoolean()){var F,me=t.readUByte();switch(me){case 1:F=[1,1];break;case 2:F=[12,11];break;case 3:F=[10,11];break;case 4:F=[16,11];break;case 5:F=[40,33];break;case 6:F=[24,11];break;case 7:F=[20,11];break;case 8:F=[32,11];break;case 9:F=[80,33];break;case 10:F=[18,11];break;case 11:F=[15,11];break;case 12:F=[64,33];break;case 13:F=[160,99];break;case 14:F=[4,3];break;case 15:F=[3,2];break;case 16:F=[2,1];break;case 255:{F=[t.readUByte()<<8|t.readUByte(),t.readUByte()<<8|t.readUByte()];break}}F&&F[0]>0&&F[1]>0&&(c=F[0]/F[1])}if(t.readBoolean()&&t.skipBits(1),t.readBoolean()&&(t.skipBits(4),t.readBoolean()&&t.skipBits(24)),t.readBoolean()&&(t.skipUEG(),t.skipUEG()),t.readBoolean()){var we=t.readUInt(),Ae=t.readUInt(),Se=t.readBoolean(),Pe=Ae/(2*we);Se&&(B=Pe)}}return{fps:B>0?B:void 0,width:Math.ceil(((f+1)*16-n*2-i*2)*c),height:(2-y)*(h+1)*16-(y?2:4)*(s+o)}}}]),r})(),G=(function(){function r(a){w(this,r),this.payload=a,this.nri=(this.payload[0]&96)>>5,this.nalUnitType=this.payload[0]&31,this._sliceType=null,this._isFirstSlice=!1}return T(r,[{key:"toString",value:function(){return"".concat(r.TYPES[this.type()]||"UNKNOWN",": NRI: ").concat(this.getNri())}},{key:"getNri",value:function(){return this.nri}},{key:"type",value:function(){return this.nalUnitType}},{key:"isKeyframe",get:function(){return this.nalUnitType===r.IDR}},{key:"isVCL",get:function(){return this.nalUnitType==r.IDR||this.nalUnitType==r.NDR}},{key:"parseHeader",value:function(){var e=new W(this.getPayload());e.readUByte(),this._isFirstSlice=e.readUEG()===0,this._sliceType=e.readUEG()}},{key:"isFirstSlice",get:function(){return this._isFirstSlice||this.parseHeader(),this._isFirstSlice}},{key:"sliceType",get:function(){return this._sliceType||this.parseHeader(),this._sliceType}},{key:"getPayload",value:function(){return this.payload}},{key:"getPayloadSize",value:function(){return this.payload.byteLength}},{key:"getSize",value:function(){return 4+this.getPayloadSize()}},{key:"getData",value:function(){var e=new Uint8Array(this.getSize()),t=new DataView(e.buffer);return t.setUint32(0,this.getSize()-4),e.set(this.getPayload(),4),e}}],[{key:"NDR",get:function(){return 1}},{key:"IDR",get:function(){return 5}},{key:"SEI",get:function(){return 6}},{key:"SPS",get:function(){return 7}},{key:"PPS",get:function(){return 8}},{key:"AUD",get:function(){return 9}},{key:"TYPES",get:function(){var e;return e={},D(e,r.IDR,"IDR"),D(e,r.SEI,"SEI"),D(e,r.SPS,"SPS"),D(e,r.PPS,"PPS"),D(e,r.NDR,"NDR"),D(e,r.AUD,"AUD"),e}}]),r})();function he(r,a){var e=new Uint8Array((r.byteLength|0)+(a.byteLength|0));return e.set(r,0),e.set(a,r.byteLength|0),e}function xe(r){var a,e,t,n="";return a=Math.floor(r),e=parseInt(a/3600,10)%24,t=parseInt(a/60,10)%60,a=a<0?0:a%60,e>0&&(n+=(e<10?"0"+e:e)+":"),n+=(t<10?"0"+t:t)+":"+(a<10?"0"+a:a),n}var N=(function(r){V(e,r);var a=A(e);function e(t,n,i){var s;return w(this,e),s=a.call(this,"H264Remuxer"),s.frameDuration=i,s.readyToDecode=!1,s.nextDts=0,s.dts=0,s.mp4track={id:g.getTrackID(),type:"video",len:0,fragmented:!0,sps:"",pps:"",fps:30,width:0,height:0,timescale:t,duration:n,samples:[]},s.samples=[],s.remainingData=new Uint8Array,s.kfCounter=0,s.pendingUnits={},s}return T(e,[{key:"resetTrack",value:function(){this.readyToDecode=!1,this.mp4track.sps="",this.mp4track.pps="",this.nextDts=0,this.dts=0,this.remainingData=new Uint8Array,this.kfCounter=0,this.pendingUnits={}}},{key:"feed",value:function(n,i,s){var o=[],c;n=he(this.remainingData,n);var u=se.extractNALu(n),d=z(u,2);return o=d[0],c=d[1],this.remainingData=c||new Uint8Array,o.length>0?(this.remux(this.getVideoFrames(o,i,s)),!0):(K("Failed to extract any NAL units from video data:",c),this.dispatch("outOfData"),!1)}},{key:"getVideoFrames",value:function(n,i,s){var o=this,c=[],u=[],d=0,f=0,h=!1,y=!1;this.pendingUnits.units&&(c=this.pendingUnits.units,y=this.pendingUnits.vcl,h=this.pendingUnits.keyFrame,this.pendingUnits={});var S=p(n),B;try{for(S.s();!(B=S.n()).done;){var M=B.value,_=new G(M);c.length&&y&&(_.isFirstSlice||!_.isVCL)&&(u.push({units:c,keyFrame:h}),c=[],h=!1,y=!1),c.push(_),h=h||_.isKeyframe,y=y||_.isVCL}}catch(P){S.e(P)}finally{S.f()}if(c.length)if(!i)this.pendingUnits={units:c,keyFrame:h,vcl:y};else if(y)u.push({units:c,keyFrame:h});else{var I=u.length-1;I>=0&&(u[I].units=u[I].units.concat(c))}return d=i?i/u.length|0:this.frameDuration,f=i?i-d*u.length:0,u.map(function(P){P.duration=d,P.compositionTimeOffset=s,f>0&&(P.duration++,f--),o.kfCounter++,P.keyFrame&&o.dispatch("keyframePosition",o.kfCounter*d/1e3)}),b("jmuxer: No. of H264 frames of the last chunk: ".concat(u.length)),u}},{key:"remux",value:function(n){var i=p(n),s;try{for(i.s();!(s=i.n()).done;){var o=s.value,c=[],u=0,d=p(o.units),f;try{for(d.s();!(f=d.n()).done;){var h=f.value;this.parseNAL(h)&&(c.push(h),u+=h.getSize())}}catch(y){d.e(y)}finally{d.f()}c.length>0&&this.readyToDecode&&(this.mp4track.len+=u,this.samples.push({units:c,size:u,keyFrame:o.keyFrame,duration:o.duration,compositionTimeOffset:o.compositionTimeOffset}))}}catch(y){i.e(y)}finally{i.f()}}},{key:"getPayload",value:function(){if(!this.isReady())return null;var n=new Uint8Array(this.mp4track.len),i=0,s=this.mp4track.samples,o,c;for(this.dts=this.nextDts;this.samples.length;){var u=this.samples.shift(),d=u.units;if(c=u.duration,c<=0){b("remuxer: invalid sample duration at DTS: ".concat(this.nextDts," :").concat(c)),this.mp4track.len-=u.size;continue}this.nextDts+=c,o={size:u.size,duration:c,cts:u.compositionTimeOffset||0,flags:{isLeading:0,isDependedOn:0,hasRedundancy:0,degradPrio:0,isNonSync:u.keyFrame?0:1,dependsOn:u.keyFrame?2:1}};var f=p(d),h;try{for(f.s();!(h=f.n()).done;){var y=h.value;n.set(y.getData(),i),i+=y.getSize()}}catch(S){f.e(S)}finally{f.f()}s.push(o)}return s.length?new Uint8Array(n.buffer,0,this.mp4track.len):null}},{key:"parseSPS",value:function(n){var i=se.readSPS(new Uint8Array(n));this.mp4track.fps=i.fps||this.mp4track.fps,this.mp4track.width=i.width,this.mp4track.height=i.height,this.mp4track.sps=[new Uint8Array(n)],this.mp4track.codec="avc1.";for(var s=new DataView(n.buffer,n.byteOffset+1,4),o=0;o<3;++o){var c=s.getUint8(o).toString(16);c.length<2&&(c="0"+c),this.mp4track.codec+=c}}},{key:"parsePPS",value:function(n){this.mp4track.pps=[new Uint8Array(n)]}},{key:"parseNAL",value:function(n){if(!n)return!1;if(n.isVCL)return!0;var i=!1;switch(n.type()){case G.PPS:this.mp4track.pps||this.parsePPS(n.getPayload()),i=!0;break;case G.SPS:this.mp4track.sps||this.parseSPS(n.getPayload()),i=!0;break;case G.AUD:b("AUD - ignoing");break;case G.SEI:b("SEI - ignoing");break}return!this.readyToDecode&&this.mp4track.pps&&this.mp4track.sps&&(this.readyToDecode=!0),i}}]),e})(g),oe=(function(){function r(){w(this,r)}return T(r,null,[{key:"extractNALu",value:function(e){for(var t=0,n=e.byteLength,i=[],s=0,o=0;t<n;){var c=e[t++];if(c===0)o++;else if(c===1&&o>=2){var u=o+1;s!==t-u&&i.push(e.subarray(s,t-u)),s=t,o=0}else o=0}var d=null;return s<n&&(d=e.subarray(s,n)),[i,d]}},{key:"removeEmulationPreventionBytes",value:function(e){for(var t=[],n=0,i=0;i<e.length;i++){var s=e[i];if(n===2&&s===3){n=0;continue}t.push(s),s===0?n++:n=0}return new Uint8Array(t)}},{key:"readSPS",value:function(e){var t=new W(e);t.readUByte(),t.readUByte(),t.readBits(4),t.readBits(3),t.readBits(1);for(var n=t.readBits(2),i=t.readBits(1),s=t.readBits(5),o=t.readUInt(),c=new Uint8Array(6),u=0;u<6;u++)c[u]=t.readUByte();var d=t.readUByte();t.readUEG();var f=t.readUEG();f===3&&t.readBits(1);var h=t.readUEG(),y=t.readUEG(),S=t.readBoolean(),B=0,M=0,_=0,I=0;S&&(B=t.readUEG(),M=t.readUEG(),_=t.readUEG(),I=t.readUEG());var P=null,pe=t.readBoolean();if(pe){var Z=t.readBoolean();if(Z){var ye=t.readUByte();ye===255&&(t.readUShort(),t.readUShort())}var ue=t.readBoolean();ue&&t.readBoolean();var F=t.readBoolean();if(F){t.readBits(3),t.readBoolean();var me=t.readBoolean();me&&(t.readUByte(),t.readUByte(),t.readUByte())}var we=t.readBoolean();we&&(t.readUEG(),t.readUEG()),t.readBoolean(),t.readBoolean(),t.readBoolean();var Ae=t.readBoolean();if(Ae){var Se=t.readUInt(),Pe=t.readUInt();t.readBoolean(),Se&&(P=Pe/(2*Se))}}var Be=f===1||f===2?2:1,Re=f===1?2:1,Le=h-Be*(M+B),Me=y-Re*(_+I);return{width:Le,height:Me,profile_space:n,tier_flag:i,profile_idc:s,profile_compatibility_flags:o,constraint_indicator_flags:c,level_idc:d,chroma_format_idc:f,fps:P}}}]),r})(),L=(function(){function r(a){w(this,r),this.payload=a,this.nalUnitType=(a[0]&126)>>1,this.nuhLayerId=(a[0]&1)<<5|(a[1]&248)>>3,this.nuhTemporalIdPlus1=a[1]&7,this._isFirstSlice=null,this._sliceType=null}return T(r,[{key:"toString",value:function(){return"".concat(r.TYPES[this.type()]||"UNKNOWN ("+this.type()+")",": Layer: ").concat(this.nuhLayerId,", Temporal Id: ").concat(this.nuhTemporalIdPlus1)}},{key:"type",value:function(){return this.nalUnitType}},{key:"isKeyframe",get:function(){return[r.IDR_W_RADL,r.IDR_N_LP,r.CRA].includes(this.nalUnitType)}},{key:"isVCL",get:function(){return this.nalUnitType<=31}},{key:"parseHeader",value:function(){var e=new W(this.getPayload());e.readUByte(),e.readUByte(),this._isFirstSlice=e.readBoolean(),this.isKeyframe&&e.readBits(1),e.readUEG(),this._sliceType=e.readUEG()}},{key:"isFirstSlice",get:function(){return this._isFirstSlice||this.parseHeader(),this._isFirstSlice}},{key:"sliceType",get:function(){return this._sliceType||this.parseHeader(),this._sliceType}},{key:"getPayload",value:function(){return this.payload}},{key:"getPayloadSize",value:function(){return this.payload.byteLength}},{key:"getSize",value:function(){return 4+this.getPayloadSize()}},{key:"getData",value:function(){var e=new Uint8Array(this.getSize()),t=new DataView(e.buffer);return t.setUint32(0,this.getSize()-4),e.set(this.getPayload(),4),e}}],[{key:"TRAIL_N",get:function(){return 0}},{key:"TRAIL_R",get:function(){return 1}},{key:"IDR_W_RADL",get:function(){return 19}},{key:"IDR_N_LP",get:function(){return 20}},{key:"CRA",get:function(){return 21}},{key:"VPS",get:function(){return 32}},{key:"SPS",get:function(){return 33}},{key:"PPS",get:function(){return 34}},{key:"AUD",get:function(){return 35}},{key:"SEI",get:function(){return 39}},{key:"SEI2",get:function(){return 40}},{key:"TYPES",get:function(){var e;return e={},D(e,r.TRAIL_N,"TRAIL_N"),D(e,r.TRAIL_R,"TRAIL_R"),D(e,r.IDR_W_RADL,"IDR"),D(e,r.IDR_N_LP,"IDR2"),D(e,r.CRA,"CRA"),D(e,r.VPS,"VPS"),D(e,r.SPS,"SPS"),D(e,r.PPS,"PPS"),D(e,r.AUD,"AUD"),D(e,r.SEI,"SEI"),D(e,r.SEI2,"SEI2"),e}}]),r})(),Ce=(function(r){V(e,r);var a=A(e);function e(t,n,i){var s;return w(this,e),s=a.call(this,"H264Remuxer"),s.frameDuration=i,s.readyToDecode=!1,s.nextDts=0,s.dts=0,s.mp4track={id:g.getTrackID(),type:"video",len:0,fragmented:!0,vps:"",sps:"",pps:"",hvcC:{},fps:30,width:0,height:0,timescale:t,duration:n,samples:[]},s.samples=[],s.remainingData=new Uint8Array,s.kfCounter=0,s.pendingUnits={},s}return T(e,[{key:"resetTrack",value:function(){this.readyToDecode=!1,this.mp4track.vps="",this.mp4track.sps="",this.mp4track.pps="",this.mp4track.hvcC={},this.nextDts=0,this.dts=0,this.remainingData=new Uint8Array,this.kfCounter=0,this.pendingUnits={}}},{key:"feed",value:function(n,i,s){var o=[],c;n=he(this.remainingData,n);var u=oe.extractNALu(n),d=z(u,2);return o=d[0],c=d[1],this.remainingData=c||new Uint8Array,o.length>0?(this.remux(this.getVideoFrames(o,i,s)),!0):(K("Failed to extract any NAL units from video data:",c),this.dispatch("outOfData"),!1)}},{key:"getVideoFrames",value:function(n,i,s){var o=this,c=[],u=[],d=0,f=0,h=!1,y=!1;this.pendingUnits.units&&(c=this.pendingUnits.units,y=this.pendingUnits.vcl,h=this.pendingUnits.keyFrame,this.pendingUnits={});var S=p(n),B;try{for(S.s();!(B=S.n()).done;){var M=B.value,_=new L(M);c.length&&y&&(_.isFirstSlice||!_.isVCL)&&(u.push({units:c,keyFrame:h}),c=[],h=!1,y=!1),c.push(_),h=h||_.isKeyframe,y=y||_.isVCL}}catch(P){S.e(P)}finally{S.f()}if(c.length)if(!i)this.pendingUnits={units:c,keyFrame:h,vcl:y};else if(y)u.push({units:c,keyFrame:h});else{var I=u.length-1;I>=0&&(u[I].units=u[I].units.concat(c))}return d=i?i/u.length|0:this.frameDuration,f=i?i-d*u.length:0,u.map(function(P){P.duration=d,P.compositionTimeOffset=s,f>0&&(P.duration++,f--),o.kfCounter++,P.keyFrame&&o.dispatch("keyframePosition",o.kfCounter*d/1e3)}),b("jmuxer: No. of H265 frames of the last chunk: ".concat(u.length)),u}},{key:"remux",value:function(n){var i=p(n),s;try{for(i.s();!(s=i.n()).done;){var o=s.value,c=[],u=0,d=p(o.units),f;try{for(d.s();!(f=d.n()).done;){var h=f.value;this.parseNAL(h)&&(c.push(h),u+=h.getSize())}}catch(y){d.e(y)}finally{d.f()}c.length>0&&this.readyToDecode&&(this.mp4track.len+=u,this.samples.push({units:c,size:u,keyFrame:o.keyFrame,duration:o.duration,compositionTimeOffset:o.compositionTimeOffset}))}}catch(y){i.e(y)}finally{i.f()}}},{key:"getPayload",value:function(){if(!this.isReady())return null;var n=new Uint8Array(this.mp4track.len),i=0,s=this.mp4track.samples,o,c;for(this.dts=this.nextDts;this.samples.length;){var u=this.samples.shift(),d=u.units;if(c=u.duration,c<=0){b("remuxer: invalid sample duration at DTS: ".concat(this.nextDts," :").concat(c)),this.mp4track.len-=u.size;continue}this.nextDts+=c,o={size:u.size,duration:c,cts:u.compositionTimeOffset||0,flags:{isLeading:0,isDependedOn:0,hasRedundancy:0,degradPrio:0,isNonSync:u.keyFrame?0:1,dependsOn:u.keyFrame?2:1}};var f=p(d),h;try{for(f.s();!(h=f.n()).done;){var y=h.value;n.set(y.getData(),i),i+=y.getSize()}}catch(S){f.e(S)}finally{f.f()}s.push(o)}return s.length?new Uint8Array(n.buffer,0,this.mp4track.len):null}},{key:"parseSPS",value:function(n){this.mp4track.sps=[new Uint8Array(n)],n=oe.removeEmulationPreventionBytes(n);var i=oe.readSPS(new Uint8Array(n));this.mp4track.fps=i.fps||this.mp4track.fps,this.mp4track.width=i.width,this.mp4track.height=i.height,this.mp4track.codec="hvc1.".concat(i.profile_idc,".").concat(i.profile_compatibility_flags.toString(16))+".L".concat(i.level_idc).concat(i.tier_flag?"H":"L")+".".concat(i.constraint_indicator_flags.map(function(s){return s.toString(16)}).join(".").toUpperCase()),this.mp4track.hvcC={profile_space:i.profile_space,tier_flag:i.tier_flag,profile_idc:i.profile_idc,profile_compatibility_flags:i.profile_compatibility_flags,constraint_indicator_flags:i.constraint_indicator_flags,level_idc:i.level_idc,chroma_format_idc:i.chroma_format_idc}}},{key:"parsePPS",value:function(n){this.mp4track.pps=[n]}},{key:"parseVPS",value:function(n){this.mp4track.vps=[n]}},{key:"parseNAL",value:function(n){if(!n)return!1;if(n.isVCL)return!0;var i=!1;switch(n.type()){case L.VPS:this.mp4track.vps||this.parseVPS(n.getPayload()),i=!0;break;case L.SPS:this.mp4track.sps||this.parseSPS(n.getPayload()),i=!0;break;case L.PPS:this.mp4track.pps||this.parsePPS(n.getPayload()),i=!0;break;case L.AUD:b("AUD - ignoing");break;case L.SEI:case L.SEI2:b("SEI - ignoing");break}return!this.readyToDecode&&this.mp4track.vps&&this.mp4track.sps&&this.mp4track.pps&&(this.readyToDecode=!0),i}}]),e})(g),De=(function(r){V(e,r);var a=A(e);function e(t,n,i,s){var o;return w(this,e),o=a.call(this,"remuxer"),o.videoCodec=i,o.frameDuration=s,o.initialized=!1,o.tracks={},o.seq=1,o.env=t,o.timescale=1e3,o.mediaDuration=n?4294967295:0,o}return T(e,[{key:"addTrack",value:function(n){var i=this;if((n==="video"||n==="both")&&(this.videoCodec=="H265"?this.tracks.video=new Ce(this.timescale,this.mediaDuration,this.frameDuration):this.tracks.video=new N(this.timescale,this.mediaDuration,this.frameDuration),this.tracks.video.on("outOfData",function(){i.dispatch("missingVideoFrames")}),this.tracks.video.on("keyframePosition",function(o){i.dispatch("keyframePosition",o)})),n==="audio"||n==="both"){var s=new J(this.timescale,this.mediaDuration,this.frameDuration);this.tracks.audio=s,this.tracks.video.on("outOfData",function(){i.dispatch("missingAudioFrames")})}}},{key:"reset",value:function(){for(var n in this.tracks)this.tracks[n].resetTrack();this.initialized=!1}},{key:"destroy",value:function(){this.tracks={},this.offAll()}},{key:"flush",value:function(){if(!this.initialized){if(!this.isReady())return;this.dispatch("ready"),this.initSegment(),this.initialized=!0}for(var n in this.tracks){var i=this.tracks[n],s=i.getPayload();if(s&&s.byteLength){var o=fe.moof(this.seq,i.dts,i.mp4track),c=fe.mdat(s),u=he(o,c),d={type:n,payload:u,dts:i.dts};n==="video"&&(d.fps=i.mp4track.fps),this.dispatch("buffer",d);var f=xe(i.dts/this.timescale);b("put segment (".concat(n,"): dts: ").concat(i.dts," frames: ").concat(i.mp4track.samples.length," second: ").concat(f)),i.flush(),this.seq++}}}},{key:"initSegment",value:function(){var n=[];for(var i in this.tracks){var s=this.tracks[i];if(this.env=="browser"){var o={type:i,payload:fe.initSegment([s.mp4track],this.mediaDuration,this.timescale)};this.dispatch("buffer",o)}else n.push(s.mp4track)}if(this.env=="node"){var c={type:"all",payload:fe.initSegment(n,this.mediaDuration,this.timescale)};this.dispatch("buffer",c)}b("Initial segment generated.")}},{key:"isReady",value:function(){for(var n in this.tracks)if(!this.tracks[n].readyToDecode||!this.tracks[n].samples.length)return!1;return!0}},{key:"feed",value:function(n){var i=!1;if(n.video&&this.tracks.video&&(i|=this.tracks.video.feed(n.video,n.duration,n.compositionTimeOffset)),n.audio&&this.tracks.audio&&(i|=this.tracks.audio.feed(n.audio,n.duration)),!i){K("Input object must have video and/or audio property. Make sure it is a valid typed array");return}this.flush()}}]),e})(le),je=(function(r){V(e,r);var a=A(e);function e(t,n){var i;return w(this,e),i=a.call(this,"buffer"),i.type=n,i.queue=new Uint8Array,i.cleaning=!1,i.pendingCleaning=0,i.cleanOffset=30,i.cleanRanges=[],i.sourceBuffer=t,i.sourceBuffer.addEventListener("updateend",function(){if(i.pendingCleaning>0&&(i.initCleanup(i.pendingCleaning),i.pendingCleaning=0),i.cleaning=!1,i.cleanRanges.length){i.doCleanup();return}}),i.sourceBuffer.addEventListener("error",function(){i.dispatch("error",{type:i.type,name:"buffer",error:"buffer error"})}),i}return T(e,[{key:"destroy",value:function(){this.queue=null,this.sourceBuffer=null,this.offAll()}},{key:"doCleanup",value:function(){if(!this.cleanRanges.length){this.cleaning=!1;return}var n=this.cleanRanges.shift();b("".concat(this.type," remove range [").concat(n[0]," - ").concat(n[1],")")),this.cleaning=!0,this.sourceBuffer.remove(n[0],n[1])}},{key:"initCleanup",value:function(n){try{if(this.sourceBuffer.updating){this.pendingCleaning=n;return}if(this.sourceBuffer.buffered&&this.sourceBuffer.buffered.length&&!this.cleaning){for(var i=0;i<this.sourceBuffer.buffered.length;++i){var s=this.sourceBuffer.buffered.start(i),o=this.sourceBuffer.buffered.end(i);n-s>this.cleanOffset&&(o=n-this.cleanOffset,s<o&&this.cleanRanges.push([s,o]))}this.doCleanup()}}catch(c){K("Error occured while cleaning ".concat(this.type," buffer - ").concat(c.name,": ").concat(c.message))}}},{key:"doAppend",value:function(){if(this.queue.length&&!(!this.sourceBuffer||this.sourceBuffer.updating))try{this.sourceBuffer.appendBuffer(this.queue),this.queue=new Uint8Array}catch(i){var n="unexpectedError";i.name==="QuotaExceededError"?(b("".concat(this.type," buffer quota full")),n="QuotaExceeded"):(K("Error occured while appending ".concat(this.type," buffer - ").concat(i.name,": ").concat(i.message)),n="InvalidStateError"),this.dispatch("error",{type:this.type,name:n,error:"buffer error"})}}},{key:"feed",value:function(n){this.queue=he(this.queue,n)}}]),e})(le),v=(function(r){V(e,r);var a=A(e);function e(t){var n;w(this,e),n=a.call(this,"jmuxer"),n.isReset=!1;var i={node:"",mode:"both",videoCodec:"H264",flushingTime:500,maxDelay:500,clearBuffer:!0,fps:30,readFpsFromTrack:!1,debug:!1,onReady:function(){},onData:function(){},onError:function(){},onUnsupportedCodec:function(){},onMissingVideoFrames:function(){},onMissingAudioFrames:function(){},onKeyframePosition:function(){},onLoggerLog:console.log,onLoggerErr:console.error};return n.options=Object.assign({},i,t),n.env=(typeof process>"u"?"undefined":ne(process))==="object"&&typeof window>"u"?"node":"browser",n.options.debug&&q(n.options.onLoggerLog,n.options.onLoggerErr),n.options.fps||(n.options.fps=30),n.frameDuration=1e3/n.options.fps|0,n.remuxController=new De(n.env,t.live,n.options.videoCodec,n.frameDuration),n.remuxController.addTrack(n.options.mode),n.initData(),n.remuxController.on("buffer",n.onBuffer.bind($(n))),n.env=="browser"&&(n.remuxController.on("ready",n.createBuffer.bind($(n))),n.initBrowser()),n.remuxController.on("missingVideoFrames",function(){typeof n.options.onMissingVideoFrames=="function"&&n.options.onMissingVideoFrames.call(null)}),n.remuxController.on("missingAudioFrames",function(){typeof n.options.onMissingAudioFrames=="function"&&n.options.onMissingAudioFrames.call(null)}),n.clearBuffer&&n.remuxController.on("keyframePosition",function(s){n.kfPosition.push(s)}),typeof n.options.onKeyframePosition=="function"&&n.remuxController.on("keyframePosition",function(s){n.options.onKeyframePosition.call(null,s)}),n}return T(e,[{key:"initData",value:function(){this.lastCleaningTime=Date.now(),this.kfPosition=[],this.pendingUnits={},this.remainingData=new Uint8Array,this.startInterval()}},{key:"initBrowser",value:function(){typeof this.options.node=="string"&&this.options.node==""&&K("no video element were found to render, provide a valid video element"),this.node=typeof this.options.node=="string"?document.getElementById(this.options.node):this.options.node,this.mseReady=!1,this.setupMSE()}},{key:"createStream",value:function(){var n=this.feed.bind(this),i=this.destroy.bind(this);return this.stream=new U.Duplex({writableObjectMode:!0,read:function(o){},write:function(o,c,u){n(o),u()},final:function(o){i(),o()}}),this.stream}},{key:"setupMSE",value:function(){if(window.MediaSource=window.MediaSource||window.WebKitMediaSource||window.ManagedMediaSource,!window.MediaSource)throw"Oops! Browser does not support Media Source Extension or Managed Media Source (IOS 17+).";if(this.isMSESupported=!!window.MediaSource,this.mediaSource=new window.MediaSource,this.url=URL.createObjectURL(this.mediaSource),window.MediaSource===window.ManagedMediaSource)try{this.node.removeAttribute("src"),this.node.disableRemotePlayback=!0;var n=document.createElement("source");n.type="video/mp4",n.src=this.url,this.node.appendChild(n),this.node.load()}catch{this.node.src=this.url}else this.node.src=this.url;this.mseEnded=!1,this.mediaSource.addEventListener("sourceopen",this.onMSEOpen.bind(this)),this.mediaSource.addEventListener("sourceclose",this.onMSEClose.bind(this)),this.mediaSource.addEventListener("webkitsourceopen",this.onMSEOpen.bind(this)),this.mediaSource.addEventListener("webkitsourceclose",this.onMSEClose.bind(this))}},{key:"endMSE",value:function(){if(!this.mseEnded)try{this.mseEnded=!0,this.mediaSource.endOfStream()}catch{K("mediasource is not available to end")}}},{key:"feed",value:function(n){!n||!this.remuxController||(n.duration=n.duration?parseInt(n.duration):0,this.remuxController.feed(n))}},{key:"destroy",value:function(){if(this.stopInterval(),this.stream&&(this.remuxController.flush(),this.stream.push(null),this.stream=null),this.remuxController&&(this.remuxController.destroy(),this.remuxController=null),this.bufferControllers){for(var n in this.bufferControllers)this.bufferControllers[n].destroy();this.bufferControllers=null,this.endMSE()}this.node=!1,this.mseReady=!1,this.videoStarted=!1,this.mediaSource=null}},{key:"reset",value:function(){if(this.stopInterval(),this.isReset=!0,this.node.pause(),this.remuxController&&this.remuxController.reset(),this.bufferControllers){for(var n in this.bufferControllers)this.bufferControllers[n].destroy();this.bufferControllers=null,this.endMSE()}this.initData(),this.env=="browser"&&this.initBrowser(),b("JMuxer was reset")}},{key:"createBuffer",value:function(){if(!(!this.mseReady||!this.remuxController||!this.remuxController.isReady()||this.bufferControllers)){this.bufferControllers={};for(var n in this.remuxController.tracks){var i=this.remuxController.tracks[n];if(!e.isSupported("".concat(n,'/mp4; codecs="').concat(i.mp4track.codec,'"')))return K("Browser does not support codec: ".concat(n,'/mp4; codecs="').concat(i.mp4track.codec,'"')),typeof this.options.onUnsupportedCodec=="function"&&this.options.onUnsupportedCodec.call(null,i.mp4track.codec),!1;var s=this.mediaSource.addSourceBuffer("".concat(n,'/mp4; codecs="').concat(i.mp4track.codec,'"'));this.bufferControllers[n]=new je(s,n),this.bufferControllers[n].on("error",this.onBufferError.bind(this))}}}},{key:"startInterval",value:function(){var n=this;this.interval=setInterval(function(){n.options.flushingTime?n.applyAndClearBuffer():n.bufferControllers&&n.cancelDelay()},this.options.flushingTime||1e3)}},{key:"stopInterval",value:function(){this.interval&&clearInterval(this.interval)}},{key:"cancelDelay",value:function(){if(this.node.buffered&&this.node.buffered.length>0&&!this.node.seeking){var n=this.node.buffered.end(0);n-this.node.currentTime>this.options.maxDelay/1e3&&(b("delay"),this.node.paused&&this.node.play().catch(K),this.node.currentTime=n-.001)}}},{key:"releaseBuffer",value:function(){for(var n in this.bufferControllers)this.bufferControllers[n].doAppend()}},{key:"applyAndClearBuffer",value:function(){this.bufferControllers&&(this.releaseBuffer(),this.clearBuffer())}},{key:"getSafeClearOffsetOfBuffer",value:function(n){for(var i=this.options.mode==="audio"&&n||0,s,o=0;o<this.kfPosition.length&&!(this.kfPosition[o]>=n);o++)s=this.kfPosition[o];return s&&(this.kfPosition=this.kfPosition.filter(function(c){return c<s&&(i=c),c>=s})),i}},{key:"clearBuffer",value:function(){if(this.options.clearBuffer&&Date.now()-this.lastCleaningTime>1e4){for(var n in this.bufferControllers){var i=this.getSafeClearOffsetOfBuffer(this.node.currentTime);this.bufferControllers[n].initCleanup(i)}this.lastCleaningTime=Date.now()}}},{key:"onBuffer",value:function(n){this.options.readFpsFromTrack&&typeof n.fps<"u"&&this.options.fps!=n.fps&&(this.options.fps=n.fps,this.frameDuration=Math.ceil(1e3/n.fps),b("JMuxer changed FPS to ".concat(n.fps," from track data"))),this.env=="browser"?this.bufferControllers&&this.bufferControllers[n.type]&&this.bufferControllers[n.type].feed(n.payload):this.stream&&this.stream.push(n.payload),this.options.onData&&this.options.onData(n.payload),this.options.flushingTime===0&&this.applyAndClearBuffer()}},{key:"onMSEOpen",value:function(){this.mseReady=!0,URL.revokeObjectURL(this.url),typeof this.options.onReady=="function"&&this.options.onReady.call(null,this.isReset)}},{key:"onMSEClose",value:function(){this.mseReady=!1,this.videoStarted=!1}},{key:"onBufferError",value:function(n){if(n.name=="QuotaExceeded"){b("JMuxer cleaning ".concat(n.type," buffer due to QuotaExceeded error")),this.bufferControllers[n.type].initCleanup(this.node.currentTime);return}else n.name=="InvalidStateError"?(b("JMuxer is reseting due to InvalidStateError"),this.reset()):this.endMSE();typeof this.options.onError=="function"&&this.options.onError.call(null,n)}}],[{key:"isSupported",value:function(n){return window.MediaSource&&window.MediaSource.isTypeSupported(n)}}]),e})(le);return v}))})(Fe)),Fe.exports}var rt=tt();const nt=Oe(rt),it=400,Ee=50;function st({deviceId:m,className:ce,onFallback:U,fallbackTimeout:R=5e3,enableControl:k=!1,onTapSuccess:O,onTapError:$,onSwipeSuccess:w,onSwipeError:C,onStreamReady:T}){const p=x.useRef(null),A=x.useRef(null),D=x.useRef(null),E=x.useRef(m),[V,te]=x.useState("connecting"),[ve,re]=x.useState(null),ae=x.useRef(null),H=x.useRef(!1),[ge,de]=x.useState([]),z=x.useRef(!1),j=x.useRef(null),[Q,X]=x.useState(null),ne=x.useRef(null),Y=x.useRef(null),ie=x.useRef(0),ee=x.useRef(null),q=x.useRef(null),[b,K]=x.useState(null),le=x.useRef(0),fe=x.useRef(0),ke=x.useRef(0),be=x.useRef(0),g=x.useRef(0),J=x.useRef(0),W=3,se=1e3,G=x.useRef(U),he=x.useRef(R),xe=x.useRef(T),N=(v,r,a)=>{const e=a.getBoundingClientRect(),t=e.width,n=e.height,i=a.videoWidth,s=a.videoHeight;if(i===0||s===0)return console.warn("[ScrcpyPlayer] Video dimensions not available yet"),null;const o=i/s,c=t/n;let u,d,f,h;c>o?(d=n,u=o*n,f=(t-u)/2,h=0):(u=t,d=t/o,f=0,h=(n-d)/2);const y=v-f,S=r-h;if(y<0||y>u||S<0||S>d)return console.warn("[ScrcpyPlayer] Click outside video area (in letterbox)"),null;const B=Math.round(y/u*i),M=Math.round(S/d*s);return console.log(`[ScrcpyPlayer] Coordinate transform:
|
|
5
|
+
Click: (${v}, ${r})
|
|
6
|
+
Display: ${t}x${n}
|
|
7
|
+
Video: ${i}x${s}
|
|
8
|
+
Rendered: ${u}x${d} at offset (${f}, ${h})
|
|
9
|
+
Device: (${B}, ${M})`),{x:B,y:M}},oe=async v=>{if(!k||!p.current||V!=="connected")return;z.current=!0,j.current={x:v.clientX,y:v.clientY,time:Date.now()};const r=p.current.getBoundingClientRect(),a=v.clientX-r.left,e=v.clientY-r.top,t=N(a,e,p.current);if(!t||!b)return;const n=p.current.videoWidth,i=p.current.videoHeight,s=b.width/n,o=b.height/i,c=Math.round(t.x*s),u=Math.round(t.y*o);try{await He(c,u,m),console.log(`[Touch] DOWN: (${c}, ${u}) for device ${m}`)}catch(d){console.error("[Touch] DOWN failed:",d)}},L=v=>{if(!z.current||!j.current)return;X({id:Date.now(),startX:j.current.x,startY:j.current.y,endX:v.clientX,endY:v.clientY});const r=p.current?.getBoundingClientRect();if(!r||!p.current||!b)return;const a=v.clientX-r.left,e=v.clientY-r.top,t=N(a,e,p.current);if(!t)return;const n=p.current.videoWidth,i=p.current.videoHeight,s=b.width/n,o=b.height/i,c=Math.round(t.x*s),u=Math.round(t.y*o),d=Date.now();d-ie.current>=Ee?(ie.current=d,Te(c,u,m).catch(f=>{console.error("[Touch] MOVE failed:",f)})):(ee.current={x:c,y:u},q.current&&clearTimeout(q.current),q.current=setTimeout(()=>{if(ee.current){const{x:f,y:h}=ee.current;ie.current=Date.now(),Te(f,h,m).catch(y=>{console.error("[Touch] MOVE (throttled) failed:",y)}),ee.current=null}},Ee-(d-ie.current)))},Ce=async v=>{if(!z.current||!j.current)return;const r=v.clientX-j.current.x,a=v.clientY-j.current.y,e=Date.now()-j.current.time;if(X(null),z.current=!1,q.current&&(clearTimeout(q.current),q.current=null),ee.current=null,Math.sqrt(r*r+a*a)<10&&e<200){je(v),j.current=null;return}const n=p.current?.getBoundingClientRect();if(!n||!p.current||!b){j.current=null;return}const i=v.clientX-n.left,s=v.clientY-n.top,o=N(i,s,p.current);if(!o){j.current=null;return}const c=p.current.videoWidth,u=p.current.videoHeight,d=b.width/c,f=b.height/u,h=Math.round(o.x*d),y=Math.round(o.y*f);try{await Ue(h,y,m),console.log(`[Touch] UP: (${h}, ${y}) for device ${m}`),O?.()}catch(S){console.error("[Touch] UP failed:",S),$?.(String(S))}j.current=null},De=async v=>{if(!k||!p.current||V!=="connected")return;const r=Date.now(),a=v.deltaY;Y.current||(Y.current={deltaY:0,lastTime:r,mouseX:v.clientX,mouseY:v.clientY}),Y.current.deltaY+=a,Y.current.lastTime=r;const e=.3;Y.current.mouseX=Math.round(Y.current.mouseX*(1-e)+v.clientX*e),Y.current.mouseY=Math.round(Y.current.mouseY*(1-e)+v.clientY*e),ne.current&&clearTimeout(ne.current),ne.current=setTimeout(async()=>{if(!Y.current||!p.current)return;const t=Y.current;if(Y.current=null,t.mouseX===void 0||t.mouseY===void 0)return;const n=p.current.getBoundingClientRect(),i=t.mouseX,s=t.mouseY,o=Math.abs(t.deltaY),c=Math.min(Math.max(300,o),800),u=N(i-n.left,s-n.top,p.current);if(!u||!b){console.warn("[ScrcpyPlayer] Cannot execute scroll: coordinate transformation failed");return}const d=p.current.videoWidth,f=p.current.videoHeight,h=b.width/d,y=b.height/f,S=Math.round(u.x*h),B=Math.round(u.y*y);let M,_;t.deltaY>0?(M=B,_=B-o):(M=B,_=B+o);const I=Math.abs(_-M),P=Math.max(I/b.height*n.height,20),pe=Math.min(Math.max(c*.8,200),800),Z=document.createElement("div");Z.style.cssText=`
|
|
10
|
+
position: fixed;
|
|
11
|
+
left: ${i}px;
|
|
12
|
+
top: ${s}px;
|
|
13
|
+
width: 20px;
|
|
14
|
+
height: 20px;
|
|
15
|
+
pointer-events: none;
|
|
16
|
+
z-index: 50;
|
|
17
|
+
transform: translateX(-50%) translateY(-50%);
|
|
18
|
+
background: radial-gradient(circle,
|
|
19
|
+
rgba(59, 130, 246, 0.8) 0%,
|
|
20
|
+
rgba(59, 130, 246, 0.4) 30%,
|
|
21
|
+
rgba(59, 130, 246, 0.2) 60%,
|
|
22
|
+
rgba(59, 130, 246, 0) 100%);
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
box-shadow: 0 0 10px rgba(59, 130, 246, 0.6);
|
|
25
|
+
`;const ye=Date.now(),ue=setInterval(()=>{const F=Date.now()-ye,me=Math.min(F/pe,1),we=t.deltaY>0?s-P*me:s+P*me;Z.style.top=we+"px",me>=1&&clearInterval(ue)},16);document.body.appendChild(Z),setTimeout(()=>{Z.parentNode&&Z.parentNode.removeChild(Z),clearInterval(ue)},pe);try{const F=await $e(S,M,S,_,c,m);F.success?w?.():C?.(F.error||"Scroll failed")}catch(F){C?.(String(F))}},it)},je=async v=>{if(!k||!p.current||V!=="connected"||p.current.videoWidth===0||p.current.videoHeight===0||!b)return;const r=p.current.getBoundingClientRect(),a=v.clientX-r.left,e=v.clientY-r.top,t=N(a,e,p.current);if(!t)return;const n=p.current.videoWidth,i=p.current.videoHeight,s=b.width/n,o=b.height/i,c=Math.round(t.x*s),u=Math.round(t.y*o),d=Date.now();de(f=>[...f,{id:d,x:v.clientX,y:v.clientY}]),setTimeout(()=>{de(f=>f.filter(h=>h.id!==d))},500);try{const f=await ze(c,u,m);f.success?O?.():$?.(f.error||"Unknown error")}catch(f){$?.(String(f))}};return x.useEffect(()=>{G.current=U,he.current=R,xe.current=T},[U,R,T]),x.useEffect(()=>{(async()=>{try{const r=await Ne(m);r.success&&(K({width:r.width,height:r.height}),console.log(`[ScrcpyPlayer] Device actual resolution: ${r.width}x${r.height} for device ${m}`))}catch(r){console.error("[ScrcpyPlayer] Failed to fetch device resolution:",r)}})()},[m]),x.useEffect(()=>{E.current=m;let v=null,r=null;const a=async()=>{if(p.current){if(console.log("[ScrcpyPlayer] connect() called"),be.current=Date.now(),te("connecting"),re(null),D.current){console.log("[ScrcpyPlayer] Closing existing WebSocket");try{D.current.onclose=null,D.current.onerror=null,D.current.onmessage=null,D.current.close()}catch(e){console.error("[ScrcpyPlayer] Error closing old WebSocket:",e)}D.current=null}if(A.current){console.log("[ScrcpyPlayer] Destroying old jMuxer instance");try{A.current.destroy()}catch(e){console.error("[ScrcpyPlayer] Error destroying old jMuxer:",e)}A.current=null}await new Promise(e=>setTimeout(e,300));try{console.log("[ScrcpyPlayer] Creating new jMuxer instance (after cleanup delay)"),A.current=new nt({node:p.current,mode:"video",flushingTime:0,fps:30,debug:!1,clearBuffer:!0,onError:i=>{if(console.error("[jMuxer] Decoder error:",i),i.name==="InvalidStateError"&&i.error==="buffer error"){const s=Date.now(),o=s-J.current;if(o<se){console.warn(`[jMuxer] Reset debounced (${o}ms since last reset)`);return}if(J.current=s,g.current++,console.warn(`[jMuxer] ⚠️ Buffer error detected (attempt ${g.current}/${W})`),g.current<=W&&A.current)try{console.log("[jMuxer] Attempting lightweight reset()..."),A.current.reset(),console.log("[jMuxer] ✓ Reset successful");return}catch(u){console.error("[jMuxer] Reset failed:",u)}console.log("[jMuxer] Reset successful, reconnecting to get fresh initialization data..."),ke.current=s;const c=e;r&&setTimeout(()=>{E.current===c?r&&r():console.log(`[jMuxer] Device changed (${c} -> ${E.current}), skip reconnect`)},100)}},onMissingVideoFrames:i=>{console.warn("[jMuxer] Missing video frames detected:",i)}});const e=E.current,t=`ws://localhost:8000/api/video/stream?device_id=${encodeURIComponent(e)}`,n=new WebSocket(t);D.current=n,n.binaryType="arraybuffer",n.onopen=()=>{console.log(`[ScrcpyPlayer] WebSocket connected for device ${e}`),te("connected"),g.current=0,J.current=0,xe.current&&xe.current({close:()=>{n.close()}}),ae.current=setTimeout(()=>{H.current||(console.log("[ScrcpyPlayer] No data received within timeout, triggering fallback"),te("error"),re("Video stream timeout"),n.close(),G.current&&G.current())},he.current)},n.onmessage=i=>{if(typeof i.data=="string"){try{const s=JSON.parse(i.data);console.error("[ScrcpyPlayer] Server error:",s),re(s.error||"Unknown error"),te("error"),G.current&&!H.current&&G.current()}catch{console.error("[ScrcpyPlayer] Received non-JSON string:",i.data)}return}if(!H.current){const s=new Uint8Array(i.data);console.log(`[ScrcpyPlayer] ✓ Received initialization data (${s.length} bytes)`);let o=0;for(let c=0;c<s.length-3;c++)s[c]===0&&s[c+1]===0&&(s[c+2]===1||s[c+2]===0&&s[c+3]===1)&&o++;console.log(`[ScrcpyPlayer] Initialization data contains ${o} NAL units`)}H.current||(H.current=!0,console.log("[ScrcpyPlayer] First video data received, canceling fallback timer"),ae.current&&(clearTimeout(ae.current),ae.current=null));try{if(A.current&&i.data.byteLength>0){const s=new Uint8Array(i.data);if(s[0]===0&&s[1]===0&&(s[2]===0||s[2]===1)||console.warn(`[ScrcpyPlayer] Invalid NAL unit: missing start code, first bytes = ${Array.from(s.slice(0,8)).map(d=>d.toString(16).padStart(2,"0")).join(" ")}`),H.current){const d=s[2]===1?3:4,f=s[d]&31;(f===5||f===7||f===8)&&console.log(`[ScrcpyPlayer] Received ${{5:"IDR",7:"SPS",8:"PPS"}[f]} NAL unit (${s.length} bytes)`)}A.current.feed({video:s}),le.current++;const c=Date.now(),u=c-fe.current;if(u>5e3){const d=le.current/u*1e3,f=p.current,h=f&&f.buffered.length>0?f.buffered.end(0)-f.currentTime:0;console.log(`[ScrcpyPlayer] Stats: ${d.toFixed(1)} fps, buffer: ${h.toFixed(2)}s`),h>2&&console.warn(`[ScrcpyPlayer] ⚠ High latency detected: ${h.toFixed(2)}s buffer`),le.current=0,fe.current=c}}}catch(s){console.error("[ScrcpyPlayer] Feed error:",s)}},n.onerror=i=>{console.error("[ScrcpyPlayer] WebSocket error:",i),re("Connection error"),te("error")},n.onclose=()=>{console.log("[ScrcpyPlayer] WebSocket closed"),te("disconnected"),xe.current&&xe.current(null);const i=e;v=setTimeout(()=>{E.current===i?(console.log("[ScrcpyPlayer] Attempting to reconnect..."),a()):console.log(`[ScrcpyPlayer] Device changed (${i} -> ${E.current}), skip reconnect`)},3e3)}}catch(e){console.error("[ScrcpyPlayer] Initialization error:",e),re("Initialization failed"),te("error")}}};return r=a,a(),()=>{if(v&&clearTimeout(v),ae.current&&(clearTimeout(ae.current),ae.current=null),D.current&&(D.current.close(),D.current=null),q.current&&(clearTimeout(q.current),q.current=null),A.current){try{A.current.destroy()}catch(e){console.error("[ScrcpyPlayer] Cleanup error:",e)}A.current=null}}},[m]),l.jsxs("div",{className:`relative w-full h-full flex items-center justify-center ${ce||""}`,children:[l.jsx("video",{ref:p,autoPlay:!0,muted:!0,playsInline:!0,onError:v=>{const a=v.currentTarget.error;a&&console.error("[Video Element] Error occurred:",{code:a.code,message:a.message,MEDIA_ERR_ABORTED:a.code===1,MEDIA_ERR_NETWORK:a.code===2,MEDIA_ERR_DECODE:a.code===3,MEDIA_ERR_SRC_NOT_SUPPORTED:a.code===4})},onMouseDown:oe,onMouseMove:L,onMouseUp:Ce,onMouseLeave:async()=>{if(z.current&&p.current&&b){if(j.current){const v=p.current.getBoundingClientRect(),r=N(j.current.x-v.left,j.current.y-v.top,p.current);if(r){const a=b.width/p.current.videoWidth,e=b.height/p.current.videoHeight,t=Math.round(r.x*a),n=Math.round(r.y*e);try{await Ue(t,n,m),console.log(`[Touch] UP (mouse leave) for device ${m}`)}catch(i){console.error("[Touch] UP (mouse leave) failed:",i)}}}z.current=!1,X(null),j.current=null}},onWheel:De,className:`max-w-full max-h-full object-contain ${k?"cursor-pointer":""}`,style:{backgroundColor:"#000"}}),k&&Q&&l.jsxs("svg",{className:"fixed inset-0 pointer-events-none z-40",children:[l.jsx("line",{x1:Q.startX,y1:Q.startY,x2:Q.endX,y2:Q.endY,stroke:"rgba(59, 130, 246, 0.8)",strokeWidth:"3",strokeLinecap:"round"}),l.jsx("circle",{cx:Q.startX,cy:Q.startY,r:"6",fill:"rgba(59, 130, 246, 0.8)"}),l.jsx("circle",{cx:Q.endX,cy:Q.endY,r:"6",fill:"rgba(239, 68, 68, 0.8)"})]}),k&&ge.map(v=>l.jsx("div",{className:"fixed pointer-events-none z-50",style:{left:v.x,top:v.y},children:l.jsx("div",{className:"ripple-circle"})},v.id)),V!=="connected"&&l.jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-black/50 backdrop-blur-sm",children:l.jsxs("div",{className:"text-center text-white",children:[V==="connecting"&&l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"w-8 h-8 border-4 border-white border-t-transparent rounded-full animate-spin mx-auto mb-2"}),l.jsx("p",{children:"正在连接..."})]}),V==="disconnected"&&l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"w-8 h-8 border-4 border-yellow-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"}),l.jsx("p",{children:"连接断开,正在重连..."})]}),V==="error"&&l.jsxs(l.Fragment,{children:[l.jsx("div",{className:"text-red-500 text-xl mb-2",children:"✗"}),l.jsx("p",{className:"text-red-400",children:"连接失败"}),ve&&l.jsx("p",{className:"text-sm text-gray-400 mt-1",children:ve})]})]})})]})}function at({deviceId:m,deviceName:ce,config:U}){const[R,k]=x.useState([]),[O,$]=x.useState(""),[w,C]=x.useState(!1),[T,p]=x.useState(null),[A,D]=x.useState(!1),[E,V]=x.useState(null),[te,ve]=x.useState(!0),[re,ae]=x.useState(!1),[H,ge]=x.useState("auto"),[de,z]=x.useState(null),[j,Q]=x.useState(()=>{try{const g=localStorage.getItem("display-tabs-visible");return g!==null?JSON.parse(g):!0}catch(g){return console.warn("Failed to load tabs visibility state:",g),!0}});x.useEffect(()=>{localStorage.setItem("display-tabs-visible",JSON.stringify(j))},[j]);const X=x.useRef(null),ne=x.useRef(null),Y=x.useRef(null),ie=x.useRef(!1),ee=x.useCallback(async()=>{if(!U){console.warn("[DevicePanel] config is required for handleInit");return}try{await Ye({model_config:{base_url:U.baseUrl||void 0,api_key:U.apiKey||void 0,model_name:U.modelName||void 0},agent_config:{device_id:m}}),D(!0),p(null)}catch(g){const J=g instanceof Error?g.message:"初始化失败,请检查配置";p(J)}},[m,U]),q=x.useCallback(async()=>{const g=O.trim();if(!g||w)return;A||await ee();const J={id:Date.now().toString(),role:"user",content:g,timestamp:new Date};k(N=>[...N,J]),$(""),C(!0),p(null);const W=[],se=[],G=(Date.now()+1).toString(),he={id:G,role:"agent",content:"",timestamp:new Date,thinking:[],actions:[],isStreaming:!0};k(N=>[...N,he]);const xe=Ve(J.content,m,N=>{W.push(N.thinking),se.push(N.action),k(oe=>oe.map(L=>L.id===G?{...L,thinking:[...W],actions:[...se],steps:N.step}:L))},N=>{k(oe=>oe.map(L=>L.id===G?{...L,content:N.message,success:N.success,isStreaming:!1}:L)),C(!1),X.current=null},N=>{k(oe=>oe.map(L=>L.id===G?{...L,content:`错误: ${N.message}`,success:!1,isStreaming:!1}:L)),C(!1),p(N.message),X.current=null});X.current=xe},[O,w,A,m,ee]),b=x.useCallback(async()=>{X.current&&X.current.close(),k([]),C(!1),p(null),X.current=null,await We(m)},[m]),K=()=>{Y.current?.scrollIntoView({behavior:"smooth"})};x.useEffect(()=>{K()},[R]),x.useEffect(()=>()=>{console.log(`[DevicePanel] 设备 ${m} 卸载,清理资源`),X.current&&(X.current.close(),X.current=null),ne.current&&(ne.current.close(),ne.current=null)},[m]),x.useEffect(()=>{if(!m||!(H==="screenshot"||H==="auto"&&re))return;const J=async()=>{if(!ie.current){ie.current=!0;try{const se=await Ne(m);se.success&&V(se)}catch(se){console.error("Failed to fetch screenshot:",se)}finally{ie.current=!1}}};J();const W=setInterval(J,500);return()=>clearInterval(W)},[m,re,H]);const le=g=>{g.key==="Enter"&&(g.metaKey||g.ctrlKey)&&(g.preventDefault(),q())},fe=x.useCallback(g=>{ne.current=g},[]),ke=x.useCallback(()=>{ae(!0),ve(!1)},[]),be=()=>{Q(!j)};return l.jsxs("div",{className:"flex-1 flex gap-4 p-4 items-stretch justify-center min-h-0",children:[l.jsxs("div",{className:"flex flex-col w-full max-w-2xl min-h-0 border border-gray-200 dark:border-gray-700 rounded-2xl shadow-lg bg-white dark:bg-gray-800",children:[l.jsxs("div",{className:"flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700 rounded-t-2xl",children:[l.jsxs("div",{children:[l.jsx("h2",{className:"text-lg font-semibold",children:ce}),l.jsx("p",{className:"text-xs text-gray-500 dark:text-gray-400",children:m})]}),l.jsxs("div",{className:"flex gap-2",children:[A?l.jsx("span",{className:"px-3 py-1 bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 rounded-full text-sm",children:"已初始化"}):l.jsx("button",{onClick:ee,className:"px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors text-sm",children:"初始化设备"}),l.jsx("button",{onClick:b,className:"px-4 py-2 bg-gray-200 dark:bg-gray-700 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors text-sm",children:"重置"})]})]}),T&&l.jsx("div",{className:"mx-4 mt-4 p-3 bg-red-100 dark:bg-red-900 text-red-700 dark:text-red-200 rounded-lg text-sm",children:T}),l.jsxs("div",{className:"flex-1 overflow-y-auto p-4 space-y-4 min-h-0",children:[R.length===0?l.jsxs("div",{className:"text-center text-gray-500 dark:text-gray-400 mt-8",children:[l.jsx("p",{className:"text-lg",children:"设备已选择"}),l.jsx("p",{className:"text-sm mt-2",children:"输入任务描述,让 AI 帮你操作手机"})]}):null,R.map(g=>l.jsx("div",{className:`flex ${g.role==="user"?"justify-end":"justify-start"}`,children:g.role==="agent"?l.jsxs("div",{className:"max-w-[80%] space-y-2",children:[g.thinking?.map((J,W)=>l.jsxs("div",{className:"bg-gray-100 dark:bg-gray-700 rounded-2xl px-4 py-3 border-l-4 border-blue-500",children:[l.jsxs("div",{className:"text-xs text-gray-500 dark:text-gray-400 mb-1",children:["💭 步骤 ",W+1," - 思考过程"]}),l.jsx("p",{className:"text-sm whitespace-pre-wrap",children:J}),g.actions?.[W]&&l.jsxs("details",{className:"mt-2 text-xs",children:[l.jsx("summary",{className:"cursor-pointer text-blue-500 hover:text-blue-600",children:"查看动作"}),l.jsx("pre",{className:"mt-1 p-2 bg-gray-800 text-gray-200 rounded overflow-x-auto text-xs",children:JSON.stringify(g.actions[W],null,2)})]})]},W)),g.content&&l.jsxs("div",{className:`rounded-2xl px-4 py-3 ${g.success===!1?"bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200":"bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200"}`,children:[l.jsx("p",{className:"whitespace-pre-wrap",children:g.content}),g.steps!==void 0&&l.jsxs("p",{className:"text-xs mt-2 opacity-70",children:["总步数: ",g.steps]})]}),g.isStreaming&&l.jsx("div",{className:"text-sm text-gray-500 dark:text-gray-400 animate-pulse",children:"正在执行..."})]}):l.jsx("div",{className:"max-w-[70%] rounded-2xl px-4 py-3 bg-blue-500 text-white",children:l.jsx("p",{className:"whitespace-pre-wrap",children:g.content})})},g.id)),l.jsx("div",{ref:Y})]}),l.jsx("div",{className:"p-4 border-t border-gray-200 dark:border-gray-700 rounded-b-2xl",children:l.jsxs("div",{className:"flex gap-2",children:[l.jsx("input",{type:"text",value:O,onChange:g=>$(g.target.value),onKeyDown:le,placeholder:A?"输入任务描述...":"请先初始化设备",disabled:w,className:"flex-1 px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-xl bg-white dark:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"}),l.jsx("button",{onClick:q,disabled:w||!O.trim(),className:"px-6 py-3 bg-blue-500 text-white rounded-xl hover:bg-blue-600 transition-colors disabled:opacity-50 disabled:cursor-not-allowed",children:"发送"})]})})]}),l.jsxs("div",{className:"w-full max-w-xs min-h-0 border border-gray-200 dark:border-gray-700 rounded-2xl shadow-lg bg-gray-900 overflow-hidden relative",children:[!j&&l.jsx("button",{onClick:be,className:"absolute top-2 right-2 z-10 w-8 h-8 bg-gray-500 hover:bg-blue-600 text-white rounded-full shadow-lg transition-all duration-300 flex items-center justify-center opacity-20 hover:opacity-100 cursor-pointer",title:"显示选项卡",children:l.jsx("svg",{className:"w-4 h-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"})})}),l.jsxs("div",{className:`${j?"absolute top-2 right-2":"hidden"} z-10 flex gap-1 bg-black/70 rounded-lg p-1`,children:[l.jsx("button",{onClick:()=>ge("auto"),className:`px-3 py-1 text-xs rounded transition-colors ${H==="auto"?"bg-blue-500 text-white":"bg-gray-700 text-gray-300 hover:bg-gray-600"}`,children:"自动"}),l.jsx("button",{onClick:()=>ge("video"),className:`px-3 py-1 text-xs rounded transition-colors ${H==="video"?"bg-blue-500 text-white":"bg-gray-700 text-gray-300 hover:bg-gray-600"}`,children:"视频流"}),l.jsx("button",{onClick:()=>ge("screenshot"),className:`px-3 py-1 text-xs rounded transition-colors ${H==="screenshot"?"bg-blue-500 text-white":"bg-gray-700 text-gray-300 hover:bg-gray-600"}`,children:"截图"}),l.jsx("button",{onClick:be,className:"ml-1 px-2 py-1 text-xs rounded transition-colors bg-gray-600 text-gray-300 hover:bg-gray-500",title:"隐藏选项卡",children:l.jsx("svg",{className:"w-3 h-3",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})})]}),H==="video"||H==="auto"&&te&&!re?l.jsxs(l.Fragment,{children:[de&&l.jsx("div",{className:"absolute top-14 right-2 z-20 px-3 py-2 bg-blue-500 text-white text-sm rounded-lg shadow-lg",children:de}),l.jsx(st,{deviceId:m,className:"w-full h-full",enableControl:!0,onFallback:ke,onTapSuccess:()=>{z("Tap executed"),setTimeout(()=>z(null),2e3)},onTapError:g=>{z(`Tap failed: ${g}`),setTimeout(()=>z(null),3e3)},onSwipeSuccess:()=>{z("Swipe executed"),setTimeout(()=>z(null),2e3)},onSwipeError:g=>{z(`Swipe failed: ${g}`),setTimeout(()=>z(null),3e3)},onStreamReady:fe,fallbackTimeout:1e5})]}):l.jsx("div",{className:"w-full h-full flex items-center justify-center bg-gray-900 min-h-0",children:E&&E.success?l.jsxs("div",{className:"relative w-full h-full flex items-center justify-center min-h-0",children:[l.jsx("img",{src:`data:image/png;base64,${E.image}`,alt:"Device Screenshot",className:"max-w-full max-h-full object-contain",style:{width:E.width>E.height?"100%":"auto",height:E.width>E.height?"auto":"100%"}}),E.is_sensitive&&l.jsx("div",{className:"absolute top-12 right-2 px-2 py-1 bg-yellow-500 text-white text-xs rounded",children:"敏感内容"}),l.jsxs("div",{className:"absolute bottom-2 left-2 px-2 py-1 bg-blue-500 text-white text-xs rounded",children:["截图模式 (0.5s 刷新)",H==="auto"&&re&&" - 视频流不可用"]})]}):E?.error?l.jsxs("div",{className:"text-center text-red-500 dark:text-red-400",children:[l.jsx("p",{className:"mb-2",children:"截图失败"}),l.jsx("p",{className:"text-xs",children:E.error})]}):l.jsxs("div",{className:"text-center text-gray-500 dark:text-gray-400",children:[l.jsx("div",{className:"w-8 h-8 border-4 border-gray-300 border-t-blue-500 rounded-full animate-spin mx-auto mb-2"}),l.jsx("p",{children:"加载中..."})]})})]})]})}function ct(){const[m,ce]=x.useState([]),[U,R]=x.useState(""),[k,O]=x.useState({baseUrl:"",apiKey:"",modelName:""}),[$,w]=x.useState(!1);return x.useEffect(()=>{const C=async()=>{try{const p=await Xe();ce(p.devices),p.devices.length>0&&!U&&R(p.devices[0].id),U&&!p.devices.find(A=>A.id===U)&&R(p.devices[0]?.id||"")}catch(p){console.error("Failed to load devices:",p)}};C();const T=setInterval(C,3e3);return()=>clearInterval(T)},[U]),l.jsxs("div",{className:"h-full flex relative min-h-0",children:[$&&l.jsx("div",{className:"absolute inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50",children:l.jsxs("div",{className:"bg-white dark:bg-gray-800 p-6 rounded-2xl w-96 shadow-xl border border-gray-200 dark:border-gray-700",children:[l.jsx("h2",{className:"text-xl font-bold mb-4 text-gray-900 dark:text-gray-100",children:"Agent 配置"}),l.jsxs("div",{className:"space-y-4",children:[l.jsxs("div",{children:[l.jsx("label",{className:"block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300",children:"Base URL"}),l.jsx("input",{type:"text",value:k.baseUrl,onChange:C=>O({...k,baseUrl:C.target.value}),placeholder:"留空使用默认值",className:"w-full px-3 py-2 border rounded-lg bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 outline-none"})]}),l.jsxs("div",{children:[l.jsx("label",{className:"block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300",children:"API Key"}),l.jsx("input",{type:"password",value:k.apiKey,onChange:C=>O({...k,apiKey:C.target.value}),placeholder:"留空使用默认值",className:"w-full px-3 py-2 border rounded-lg bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 outline-none"})]}),l.jsxs("div",{children:[l.jsx("label",{className:"block text-sm font-medium mb-1 text-gray-700 dark:text-gray-300",children:"Model Name"}),l.jsx("input",{type:"text",value:k.modelName,onChange:C=>O({...k,modelName:C.target.value}),placeholder:"留空使用默认值",className:"w-full px-3 py-2 border rounded-lg bg-white dark:bg-gray-700 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 outline-none"})]}),l.jsxs("div",{className:"flex justify-end gap-2 mt-6",children:[l.jsx("button",{onClick:()=>w(!1),className:"px-4 py-2 text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200",children:"取消"}),l.jsx("button",{onClick:()=>w(!1),className:"px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors",children:"确认配置"})]})]})]})}),l.jsx(Je,{devices:m,currentDeviceId:U,onSelectDevice:R,onOpenConfig:()=>w(!0)}),l.jsx("div",{className:"flex-1 relative flex items-stretch justify-center min-h-0",children:m.length===0?l.jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-gray-50 dark:bg-gray-900",children:l.jsxs("div",{className:"text-center text-gray-500 dark:text-gray-400",children:[l.jsx("svg",{className:"w-16 h-16 mx-auto mb-4 opacity-50",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"})}),l.jsx("h3",{className:"text-lg font-medium mb-2",children:"欢迎使用 AutoGLM Chat"}),l.jsx("p",{className:"text-sm",children:"未检测到设备,请连接 ADB 设备"})]})}):m.map(C=>l.jsx("div",{className:`w-full h-full flex items-stretch justify-center min-h-0 ${C.id===U?"":"hidden"}`,children:l.jsx(at,{deviceId:C.id,deviceName:C.model,config:k,isVisible:C.id===U})},C.id))})]})}export{ct as component};
|