Commit Graph
381 Commits
Author SHA1 Message Date
IgorA100 141023dd98 Clear mseSourceBuffer only if the number of buffers is greater than zero. (MonitorStream.js) 2026-07-05 17:41:45 +03:00
Isaac ConnorandClaude Opus 4.8 8b9546df33 fix: fall back from go2rtc player when no video is delivered
When a go2rtc player connects but the source video codec cannot be decoded by
the browser (e.g. an H.265 camera viewed in Chrome, which supports HEVC over
neither WebRTC nor MSE), go2rtc negotiates the video track as inactive and
sends only audio. The video element "plays" audio with no picture and stays at
0x0, so the normal 'error' handler never fires and the player hangs on
"Loading..." indefinitely.

Add a watchdog armed when a go2rtc stream starts: if no video frame is decoded
within NO_VIDEO_TIMEOUT, register a playback error and advance through the
existing player-priority fallback (eventually ZMS MJPEG), which can render the
stream server-side. The watchdog is cleared on stop()/restart() so it never
fires against a subsequently selected player.

Verified in-browser on a 3840x2160 H.265 monitor: go2rtc_webrtc -> go2rtc_mse
-> zms, ending on a visible MJPEG image instead of an endless "Loading...".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 12:41:52 -04:00
Isaac ConnorandClaude Opus 4.8 ce1474667a fix: stop montage zms <img> reconnect storm on stale auth hash
A live multipart (mode=jpeg) stream <img> whose baked auth hash expires
past AUTH_HASH_TTL is reconnected by the browser itself, reusing the same
src (same connkey, same dead hash). Every native reconnect returns 403, so
once the capture daemon drops the stream the client storms zms with auth
failures for hours. Observed in production: a single connkey retried 84
times over 2.5h, 880 failures on one monitor whose zmc was timing out,
while monitors with healthy zmc showed only baseline hash-rollover noise.

img_onerror only blanked the <img> src inside its async refresh callback,
which never ran once authRefreshAttempts reached the cap. On give-up the
stale src stayed live and the browser kept native-retrying it, which is the
storm. Blank src synchronously at the top of img_onerror so the browser's
retry loop stops immediately, and reconnect with a fresh connkey (the zms
process behind the old connkey has exited) after fetching a fresh hash.

Extract the src rewrite into a pure rebuildStreamSrc() helper in
auth-helpers.js with unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:15:28 -04:00
Isaac Connor 2d0cc2250c Merge pull request #4883 from IgorA100/patch-10343
Feat: Correctly iterates through players when the Player = "Auto" mode is selected.
2026-06-09 18:17:11 -04:00
IgorA100andCopilot Autofix powered by AI 4818711a1c Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-06 23:41:50 +03:00
IgorA100 3204c0d5bb When looping through players, check if it's enabled for the monitor. (MonitorStream.js)
And don't execute removeEventListener for 'volumechange' in the stream error handler, as it will be executed in restart()->stop()
2026-06-06 22:12:35 +03:00
Isaac ConnorandClaude Opus 4.8 a55d167b91 feat: refresh auth hash on tab resume, redirect to login on dead session refs #4748
When a console or stream tab is backgrounded or the machine sleeps past the
auth hash TTL, the baked-in auth= on nph-zms <img> URLs expires. The browser
keeps reconnecting with the stale hash, producing a burst of 403s from zms
while the session-backed page still renders.

Detect the tab becoming visible again (visibilitychange/pageshow) and probe
auth once against the navBar status endpoint before letting streams reconnect:
on success refresh the global auth_hash and repaint; on a dead session (401)
go straight to login instead of retrying. Route the navBar poll, console table
query, and per-stream error paths through a shared decision so 401/403 ends in
a single login redirect rather than a retry storm.

Put the auth functions (goToLogin, revalidateAuth, onAuthVisible) and the pure
authFailureAction/loginRedirectUrl helpers in web/js/auth-helpers.js as named
globals; skin.js only wires the visibility listeners. Node unit tests cover the
pure helpers (tests/js/auth-helpers.test.js).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 10:26:15 -04:00
IgorA100 5816cca859 Recovered the spaces lost by Copilot (MonitorStream.js) 2026-06-05 16:16:00 +03:00
IgorA100andCopilot Autofix powered by AI 88d54d4f1e Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-05 16:12:48 +03:00
IgorA100 4449afd542 Added a missing space. (MonitorStream.js) 2026-06-05 11:40:43 +03:00
IgorA100 d035eb0cab Fix: Iterating over players for Player=Auto mode (MonitorStream.js)
- playerPriority is now a stream object, not a global constant.
- To assign an error listener, use this.handlerEventListener['errorStream'] instead of the erroneous this.handlerEventListener['playStream'] and clear it when the stream stops.
- New algorithm for iterating over players in selectNextPlayer()
- For Janus, use monitorStream.streamErrorRegistration() instead of the erroneous this.streamErrorRegistration()
2026-06-05 11:37:51 +03:00
IgorA100 f5d1fac68c Fix: ESLint (MonitorStream.js) 2026-06-04 17:40:46 +03:00
IgorA100 550fee2384 Correctly iterates through players when the Player = "Auto" mode is selected. (MonitorStream.js) 2026-06-04 17:25:00 +03:00
IgorA100andCopilot Autofix powered by AI 1e7691c9b4 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-05 09:53:25 +03:00
IgorA100 3e07024c8e Prevent pointless setInterval(this.statusCmdQuery) calls for "frozen" objects. (MonitorStream.js)
This PR doesn't fix the root cause of the issue, but addresses the consequences.
I spent time investigating the problem, but I couldn't figure out the root cause because it's difficult to debug.
Perhaps I'll revisit this issue later.
For now, let's leave it at that.
2026-06-05 00:28:10 +03:00
Isaac Connor c8d47e6f31 Merge pull request #4841 from IgorA100/patch-818041
FixL Correctly save setCookie('zmWatchMuted') when "=false" (MonitorStream.js)
2026-05-24 18:55:25 -04:00
IgorA100 ac13e84ace Fix: Correct reading of zmWatchMuted cookies 2026-05-24 22:28:05 +03:00
IgorA100 9e8f10288f Correctly save setCookie('zmWatchMuted') when "=false" (MonitorStream.js) 2026-05-21 13:54:23 +03:00
Isaac ConnorandClaude Opus 4.7 6db9b29158 feat: refresh auth hash and retry on MonitorStream image error
zms returns 403 on a stale auth hash (default TTL 2h), but the live
<img src=nph-zms?...> keeps the original src and reconnects forever
with the expired hash, generating one zms warning per retry until the
user reloads the page.

On img_onerror, fetch a fresh auth hash from the existing navBar
status endpoint, splice it into the img src, and reconnect. Capped at
3 attempts with 2s/4s/8s backoff so a genuinely-down camera doesn't
loop indefinitely. img_onload resets the attempt counter on success.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 23:00:59 -04:00
copilot-swe-agent[bot]andconnortechnology 1be352c790 fix: add stopped state for CMD_STOP, fixing paused=true response bug
When CMD_STOP is sent via AJAX using ZMS MJPEG streaming, the response
was incorrectly returning paused=true instead of indicating a stopped
state (paused=false).

Changes:
- Add `stopped` boolean to StreamBase (zm_stream.h)
- MonitorStream: CMD_STOP now sets stopped=true, paused=false instead
  of paused=true; run loop skips frame sending when stopped
- EventStream: CMD_STOP sets stopped=true (was already setting
  paused=false); run loop skips frame sending when stopped
- All other play/pause commands reset stopped=false
- Both streams include stopped field in the status response struct
- stream.php unpacks the new stopped field from MSG_DATA_WATCH and
  MSG_DATA_EVENT responses
- MonitorStream.js handles stopped status in UI (shows 'Stopped' mode)
- EventStream.js tracks stopped state from server response

Fixes issue: CMD_STOP response paused=true should be paused=false

Agent-Logs-Url: https://github.com/ZoneMinder/zoneminder/sessions/ba9cb47a-a3e8-4e13-aec7-c9cd258e2a3d

Co-authored-by: connortechnology <925519+connortechnology@users.noreply.github.com>
2026-05-06 01:58:48 +00:00
IgorA100andCopilot ce9c93dc5a Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-29 16:01:10 +03:00
IgorA100 5d958111ff We'll now pause audioMotion in MonitorStream.js. (MonitorStream.js) 2026-04-28 16:27:17 +03:00
IgorA100 79e5a56b80 Adjusting the display of the "infoBlock" block (MonitorStream.js) 2026-04-23 00:01:10 +03:00
IgorA100 f8df2fa0c0 Merge branch 'master' into patch-435415 2026-04-11 14:51:53 +03:00
Isaac Connor 3ac03fa8c9 Merge pull request #4721 from IgorA100/patch-990359
Fix: Prevent vertical shifting of #content on the Watch page when displaying the stream status overlay. on Watch page
2026-04-10 10:16:12 -04:00
Isaac ConnorandClaude Opus 4.6 692b77b4da fix: guard against empty auth_relay producing double && in zms URLs
When auth is disabled or auth_relay is empty, appending '&'+auth_relay
produces a trailing '&' which results in double '&&' when the next
parameter is appended (e.g. ?monitor=2&&scale=41&mode=single).

Guard all 4 places in MonitorStream.js where auth_relay is concatenated
into URLs, consistent with EventStream.js which already guards this.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 12:27:56 -04:00
IgorA100 bbe1b6f00e Update MonitorStream.js 2026-03-28 00:00:44 +03:00
IgorA100 d8ada88da7 Update MonitorStream.js 2026-03-27 23:57:50 +03:00
IgorA100 f3a2910e93 Instead of audioMotion.play(), use audioMotion.init() (MonitorStream.js) 2026-03-21 22:12:27 +03:00
IgorA100 b4dc754506 Fix: Eslint (MonitorStream.js) 2026-03-19 12:39:33 +03:00
IgorA100 89a983984e Merge branch 'ZoneMinder:master' into patch-435415 2026-03-19 12:33:45 +03:00
IgorA100 1a1c219e26 skin.js
- Clear IconMute when executing destroyVolumeSlider()
- Added the ability to clear the icon state to changeStateIconMute()

MonitorStream.js
- Set #volumeControls to "disabled" instead of "hidden"
- Don't execute controlMute() when executing createVolumeSlider()

Added:
audioMotionAnalyzer.js
2026-03-19 12:28:47 +03:00
IgorA100 1af54ad008 Creating a volume slider on the Montage page to simultaneously control the volume of all monitors
Moving the volume slider control portion from MonitorStream.js to skin.js
2026-03-18 14:16:28 +03:00
IgorA100 1fc68a3e84 If the system volume was set to 0, change the state of the "Mute" icon in the volume slider (MonitorStream.js) 2026-03-18 13:32:01 +03:00
IgorA100 d9361ea63e Fix parent 2026-03-16 19:08:09 +03:00
IgorA100 82095fe9d8 If we don't display the video, then display the information block on "#monitorXX" 2026-03-16 19:03:32 +03:00
Isaac ConnorandClaude Opus 4.6 5561829450 fix: include username in auth relay and fix stale auth in stream restart
- Add user= parameter to get_auth_relay() so zms can use the indexed
  Username column instead of iterating all users to validate the hash
- Apply the same fix to Event.php getStreamSrc() and getThumbnailSrc()
- Tighten Monitor.php from isset() to !empty() for consistency
- In MonitorStream.js start(), check if the auth hash in the img src
  matches the current auth_hash before resuming via CMD_PLAY. If stale,
  fall through to rebuild the URL with fresh auth_relay. This prevents
  long-running montage pages from spawning zms with expired credentials.
- Downgrade zms auth failure from Error to Warning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 10:01:47 -04:00
IgorA100 524ab91cc3 Added audio visualization 2026-03-15 00:50:35 +03:00
IgorA100 f536252a85 Set "pointer-events: none" for "imgInfoBlock" and "infoBlock" to disable pointer events for them (MonitorStream.js) 2026-03-14 17:16:39 +03:00
IgorA100 94b1ead0f4 When stopping a stream, execute writeTextInfoBlock after checking the existence of the stream (MonitorStream.js) 2026-03-14 16:07:50 +03:00
IgorA100andCopilot Autofix powered by AI d43dd30155 Normalizing text before assigning it to a DOM element
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-14 15:45:01 +03:00
IgorA100 dcd3ef06ad Instead of explicitly specifying the text size, we use a call to the new function "setTextSizeOnInfoBlock" (MonitorStream.js)
This will allow us to correctly specify the class for the block.
2026-03-13 11:43:42 +03:00
IgorA100 33783300bd Fix: Eslint (MonitorStream.js) 2026-03-12 23:58:27 +03:00
IgorA100 d00f56d036 When a stream is loaded, paused, or stopped, display a corresponding caption in the center of the stream player. (MonitorStream.js)
Additionally, when loading or stopping a stream using Go2RTC, RTSP2Web, or Janus, display a static image generated at that moment.
2026-03-12 23:41:32 +03:00
IgorA100 7d833bd8bb Fix Eslint (MonitorStream.js) 2026-03-11 18:57:16 +03:00
IgorA100 1478594780 Code optimization (MonitorStream.js)
- getAudioStream has been renamed to getAVStream
- Clear this.handlerEventListener['volumechange'] when the stream is stopped
- Check volumeSlider.noUiSlider after assigning the listener
- This.handlerEventListenerStream does not require an argument (stream), but if we have already received a stream, we will pass it as an argument to avoid searching for the stream again.
2026-03-11 18:53:05 +03:00
IgorA100andCopilot 23fd92ef3a Update web/js/MonitorStream.js
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-11 18:08:59 +03:00
IgorA100 ced61c1c7d Update MonitorStream.js 2026-03-10 17:59:45 +03:00
IgorA100 2bf9d415da The listener assignment has been moved above the noUiSlider check (MonitorStream.js).
I also removed the unnecessary code for checking the presence of audioStream.
2026-03-10 10:57:01 +03:00
IgorA100 aa7aa38d70 Using "manageEventListener" for the 'volumechange' event (MonitorStream.js) 2026-03-10 01:07:15 +03:00