Reverts the previous commit's always-on measurement. Decoding audio for every
monitor that has it spends CPU on a number almost nothing reads, which is the
wrong trade even though it did solve the chicken and egg of picking a
threshold without ever seeing a level.
Measure when something is actually going to use the reading instead:
- AudioDetection is on, as before, so nothing changes for a monitor that
scores on audio; or
- somebody asked. SharedData gains audio_level_until, a wall clock second
the capture thread keeps measuring up to. The monitor editor's new level
meter pushes it forward while it is on screen and the measurement lapses a
few seconds after the page is left, so nothing has to send a stop and a
crashed browser cannot leave a monitor decoding forever.
When the reading stops being wanted the decoder is released and the published
level and peak are cleared, so a stale number is not left looking current and
an old peak does not land on the next frame row written.
audio_level_until is carved out of analysis_pad rather than appended, so
SharedData stays 888 bytes and no existing offset moves; the static_asserts,
Memory.pm and Monitor.php are updated together and all three now agree the
field is at +880.
The meter itself is on the audio settings, shown whether or not
AudioDetection is checked, because the level is what you need in order to
choose a threshold. It draws the threshold currently in the input as a mark on
the bar so a reading can be judged against it before saving, and a monitor
whose zmc is not running reads "no reading" rather than a confident 0, which
would be indistinguishable from silence.
Frames.AudioLevel is therefore 0 again on monitors that do not score on audio.
That is what the graph already treats as "no audio data", so it draws no line
rather than a flat one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JpiSWBmtQkR5bcgpHWY4ME
web/ajax/monitor.php built its permission-error text with
translate('СonjOr'), where the leading С is Cyrillic Es (U+0421), not
Latin C. Two consequences:
- The lookup key did not match the defined 'ConjOr' translation (Latin C,
en_gb.php), so translate() fell through to echoing the raw key instead of
the conjunction "or".
- The multi-byte UTF-8 sequence (0xD0 0xA1) is corrupted by some reverse
proxies, surfacing as a stray control byte in the served response.
Use the Latin 'ConjOr' key, matching every other caller (e.g.
web/includes/FilterTerm.php). A full Cyrillic/Greek homoglyph sweep of the
first-party tree (excluding lang/ and vendored assets) found this as the
only remaining occurrence.
refs https://github.com/ZoneMinder/zoneminder/discussions/4993
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KQipwf632JGgNH4W7p8cqs
- Added translations for English and Russian.
- Added a method to the Monitor class for retrieving default settings. This is necessary to retrieve the 'filter_regexp' of the monitor name, so as not to re-specify 'filter_regexp' during an AJAX request.
- Added the \web\ajax\monitor.php file.