Skip to content

Repository files navigation

VolumeSentinel for Android

Stop sudden loud audio from blasting your ears.

VolumeSentinel watches your Android device’s media audio in real time. When a spike exceeds your threshold, it instantly cuts the media volume, then gradually restores it when things quiet down.

Inspired by the Windows version, this Android edition brings the same hearing protection to mobile — especially for headphone and IEM users.

中文说明见 README.zh-CN.md · 架构见 ARCHITECTURE.md · 变更记录见 CHANGELOG.md

Features

  • Dual capture engine — MediaProjection (true look-ahead) or Visualizer API (no screen share)
  • Real-time peak detection — analyzes audio every ~10 ms with configurable danger confirmation
  • Look-ahead buffer — 20 ms pre-emptive analysis (MediaProjection mode)
  • Smart recovery — gradual volume restoration with hold delay and step control
  • Per-device profiles — independent settings for speaker, wired headphones, Bluetooth, USB DAC
  • Per-engine settings — switching engines loads the matching parameter set (mp_ / viz_)
  • Audition preview — play a reference tone at the threshold level to calibrate by ear
  • 0–100 loudness mapping — Visualizer mode maps dBFS to an intuitive 0–100 scale
  • Volume compensation — prevents oscillation during sustained loud audio (Visualizer mode)
  • Foreground service — persistent background protection with notification-bar status

Requirements

  • Android 10 (API 29) or later
  • No root required

Installation

Prebuilt APK (recommended)

Download the latest APK from Releases.

Release builds may be unsigned. Android will ask you to allow installs from unknown sources. Prefer building and signing yourself for production use.

Build from source

# Prerequisites: Android Studio Hedgehog+ (JDK 17+), Android SDK 34

git clone git@github.com:yaki1210/VolumeSentinel-Android.git
cd VolumeSentinel-Android
./gradlew assembleDebug        # debug APK
./gradlew assembleRelease      # release APK (unsigned unless you configure signing)

# Outputs:
#   app/build/outputs/apk/debug/app-debug.apk
#   app/build/outputs/apk/release/app-release-unsigned.apk

Windows:

gradlew.bat assembleDebug

Quick start

  1. Install the APK and launch VolumeSentinel
  2. Grant microphone and notifications permissions
  3. Choose a capture engine (see comparison below)
  4. Adjust Trigger Threshold — tap ▶ to audition the threshold loudness
  5. Set Safe Volume Level — volume used while protecting
  6. Toggle the main switch to start protection

Status in the persistent notification:

Status Meaning
SAFE Monitoring, no danger
PROTECTING Volume reduced due to a spike
RECOVERING Gradually restoring volume

Capture engines — which one should I use?

VolumeSentinel offers two independent capture engines. They measure audio at different points in the playback path, so their readings, defaults, and trade-offs differ a lot. Do not copy thresholds between engines.

MediaProjection Visualizer
Capture position Pre-volume (content loudness, before system volume) Post-volume (after STREAM_MUSIC volume)
Signal Full PCM 16-bit / 48 kHz / stereo Peak & RMS in millibels (mB → dBFS)
Look-ahead Yes (~20 ms ring buffer) No (real-time poll only)
Screen-share dialog Required every session / after token expiry Not needed
Typical threshold around −12 dBFS around −50 dBFS (or ~loudness 50/100)
Stability MediaProjection token may expire Watchdog re-attaches after stuck silence
Foreground service type MEDIA_PROJECTION MICROPHONE
Best for Highest accuracy, true look-ahead, calibration close to Windows Everyday use without screen-share UI, fewer interruptions

MediaProjection (recommended when accuracy matters)

  • Captures the original media signal before system volume is applied — same idea as Windows WASAPI loopback.
  • Look-ahead lets the app react slightly before the loud part is fully heard.
  • Requires the system screen / media projection consent dialog. On many devices this can affect notifications or show a persistent “casting / sharing” indicator.
  • If the projection token expires, protection pauses until you re-authorize (the app can prompt via the notification / UI).

Visualizer (recommended for convenience)

  • Attaches to the global output mix (session 0) via the Visualizer API.
  • Only needs mic + audio-settings permissions — no screen share.
  • Because capture is after volume, lowering volume also lowers the measured peak. The controller applies volume compensation so sustained loud content does not oscillate between protect and recover.
  • Readings are typically much lower than MediaProjection for the same content — always calibrate on this engine’s own meter / audition tone.
  • A watchdog briefly restarts Visualizer after ~50 consecutive silence frames (~500 ms at 10 ms poll) when the API gets stuck after app/device switches.

Mental model

Media apps ──► [pre-volume] ──► system volume ──► [post-volume] ──► speaker / headphones
                    ▲                                   ▲
              MediaProjection                      Visualizer

Parameter guide (experience & reference)

Settings are stored per engine and per output device. Switching engine or plugging headphones loads the matching set.

Basic parameters

Parameter Default (MP) Default (Viz) What it does Tuning tips
Trigger Threshold −12 dBFS −50 dBFS Peak level that starts protection Start near default. Use ▶ audition. Lower (more negative) = more sensitive / triggers earlier. Raise if it fires on normal peaks.
Safe Volume Level 5% 5% Volume while protecting Headphones/IEM: 3–8%. Speaker: 10–20% is often fine. Too low can feel like mute on devices with few volume steps.
Recovery Delay (hold) 500 ms 800 ms Quiet time before recovery starts Increase if content has frequent short gaps (ads, game SFX). Viz defaults higher because there is no look-ahead.
Recovery Step 10% 8% Volume increase per recovery step Smaller = smoother / less “pumping”. Larger = snappier return to full volume.

Advanced parameters

Parameter Default What it does Tuning tips
Poll Interval 10 ms How often peaks are sampled 10 ms is a good balance. Higher saves a bit of CPU but increases reaction latency.
Danger Frames 1 (MP) / 2 (Viz) Consecutive dangerous frames required Raise to 2–3 if single-frame spikes false-trigger (especially Visualizer). Lower for fastest reaction.
Lookback Frames 2 Historical peak window size Slightly larger window smooths flicker; too large delays “all clear”.
Look-Ahead Buffer 20 ms Pre-emptive window (MP only) 10–30 ms is typical. Higher uses more memory/latency budget; Visualizer ignores this.

Per-device starting points (MediaProjection-style defaults in code)

These are type defaults used when a device has no custom profile yet (MediaProjection-oriented). On Visualizer, still re-calibrate with the on-screen meter.

Output Threshold (ref.) Safe vol. Hold Notes
Built-in speaker ~−8 dBFS ~15% ~400 ms More forgiving; room noise / lower risk
Wired / USB headset ~−15 dBFS ~5% ~600 ms Most critical for hearing protection
Bluetooth A2DP ~−14 dBFS ~5% ~500 ms Codec / latency vary by device

Practical calibration workflow

  1. Pick the engine you will actually use daily.
  2. Play representative content (the apps that surprised you before).
  3. Watch the live peak meter during normal loud parts vs. spikes.
  4. Set threshold slightly above normal peaks, below the spikes you hate — or use ▶ audition.
  5. Trigger protection once on purpose; confirm Safe Volume is still listenable, not silent.
  6. If it chatters (protect ↔ recover rapidly): raise threshold a little, increase hold, or raise danger frames.
  7. If it misses spikes: lower threshold, lower danger frames (MP), ensure poll stays ~10 ms.
  8. Plug headphones and re-check — profiles are per device; don’t assume speaker settings transfer.

Visualizer-only notes

  • Threshold UI shows dBFS (loudness/100). Use loudness as a human-friendly scale; the engine still decides in dBFS.
  • After a volume duck, compensation reconstructs “content loudness” so recovery waits for real quiet, not for the duck itself.
  • If the meter freezes at silence while audio plays, wait for the watchdog (~0.5 s) or toggle protection once.

Usage notes & cautions

Permissions & system behavior

  • RECORD_AUDIO is required for both engines (Android’s capture APIs), even though this app is not a traditional “microphone recorder” for your voice.
  • POST_NOTIFICATIONS (Android 13+) is required for the status notification; without it, background status is hard to see.
  • MediaProjection may show a system “screen sharing / casting” indicator and can interact poorly with some OEMs’ notification policies.
  • Some OEMs (Xiaomi, Huawei, Oppo, Vivo, Samsung, etc.) aggressively kill background apps — whitelist VolumeSentinel / allow “autostart” / disable battery restrictions for reliable protection.

What is protected / not protected

Typically works with: YouTube, Bilibili, Netflix, games, browser video, music players, local video.

Not supported / not intended: phone calls, VoLTE, voice messages, video-conference call audio (separate Android audio paths; ordinary apps should not duck call audio).

Hearing & safety disclaimer

  • This tool reduces system media volume after detection. It is not a medical device, not a substitute for safe listening levels, and not a guarantee against all sudden loudness (especially Visualizer without look-ahead, or after projection expiry).
  • Always use reasonable base volume. Protection is a safety net, not permission to max the volume slider.
  • On devices with few volume steps, very low Safe Volume % may round to near-mute — raise it slightly if recovery seems stuck silent (fixed path uses roundToInt, but hardware steps still limit resolution).

Operational tips

  • Prefer leaving the notification visible so you can see SAFE / PROTECTING / RECOVERING.
  • After long standby or audio-route changes, confirm the service is still running.
  • Switching engines does not copy thresholds — each engine keeps its own calibration.
  • Changing device (BT ↔ wired) switches profiles automatically; customize each if needed.
  • Debug builds are larger and slower; use release APK for daily use once you trust a build.

Privacy

  • Audio is analyzed on device for peaks. The app does not upload audio content.
  • MediaProjection is used for playback capture, not for recording your screen to disk.

Configuration storage

Scope Keys / mechanism
Global enabled, capture_mode
Per engine mp_* / viz_* prefixed SharedPreferences
Per device JSON profiles in a separate prefs file

Legacy unprefixed keys are migrated once to the mp_ prefix on first load.

Project structure

app/src/main/java/com/volumesentinel/android/
├── MainActivity.kt                 # Entry, permissions
├── audio/
│   ├── CaptureMode.kt              # Engine selection
│   ├── AudioCaptureEngine.kt       # MediaProjection capture
│   ├── VisualizerCaptureEngine.kt  # Visualizer API capture
│   ├── AudioFrameBuffer.kt         # Look-ahead ring buffer
│   ├── PeakDetector.kt             # PCM peak / RMS analysis
│   ├── VolumeController.kt         # STREAM_MUSIC volume
│   └── AuditionPlayer.kt           # Threshold preview tone
├── config/
│   └── ProtectionConfig.kt         # Per-mode persisted settings
├── device/
│   ├── AudioDeviceMonitor.kt       # Output device detection
│   └── DeviceProfileManager.kt     # Per-device profiles
├── protection/
│   ├── ProtectionController.kt     # State machine + compensation
│   └── ProtectionState.kt
├── service/
│   └── ProtectionService.kt        # Foreground orchestrator
└── ui/
    ├── MainScreen.kt
    └── theme/

Development

./gradlew test                 # unit tests
./gradlew assembleDebug        # debug APK
./gradlew assembleRelease      # release APK

Stack: Kotlin, Jetpack Compose, Foreground Service, MediaProjection / Visualizer, minSdk 29, targetSdk 34.

Versioning

Current version: 1.1.0 (versionCode 2). See CHANGELOG.md.

Platform Compatibility & Known Issues

Android 14 (Color OS) Background Restrictions

Color OS (based on Android 14) employs additional background management policies. Even with "Allow background operation" enabled, the system may:

  • Suspend the service's volume control capability after prolonged inactivity
  • Freeze the app process in the background, preventing it from responding to audio changes
  • Throttle frequent notification updates, indirectly affecting service liveness

Symptoms: The protection notification remains visible, but volume changes are no longer applied. Reopening the app restores normal behavior.

Workarounds:

  1. Add VolumeSentinel to the "Unrestricted battery optimization" whitelist
  2. Lock the app in the recent tasks menu
  3. Disable "Smart power saving" or "Auto freeze" for VolumeSentinel in system settings
  4. If all else fails, check Developer Options for background process limits

Android 16 (AOSP)

Pure Android 16 provides reliable foreground service scheduling. After disabling battery optimization, VolumeSentinel runs perfectly in the background with consistent volume protection behavior.

General Recommendations

  • Always add VolumeSentinel to the battery optimization whitelist on all platforms
  • If protection stops responding, simply reopen the app to restore functionality — no need to restart the service
  • The Visualizer engine (no screen-share consent) may be more stable on certain ROMs

License

MIT — free to use, share, and modify.

Acknowledgments

About

Android real-time audio spike protector with dual capture engines (MediaProjection / Visualizer), per-device profiles, and hearing protection for headphones.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages