Janus
"two faces, one purpose"
android BLE GATT server named after the roman god of transitions and duality. exposes your phone's media as bluetooth low energy characteristics. universal media control for any device. works with spotify, apple music, youtube music, or any android media player.
features
universal media control
hooks into android's MediaSession API. works with any music app that follows android standards. spotify, youtube music, apple music, tidal, soundcloud - all supported automatically.
album art transfer
chunked BLE transfer of album artwork. resizes images to fit BLE MTU limits, encodes as base64, sends in sequential chunks. mercury reassembles on the car thing side.
lyrics sync
fetches time-synced lyrics in LRC format. displays lyrics on the car thing display in real-time with the music. highlights current line based on playback position.
GATT characteristics
janus exposes media data through custom BLE GATT characteristics. mercury scans for these UUIDs and reads the data.
| UUID | Characteristic | Format |
|---|---|---|
| 0x2001 | Track Title | UTF-8 string |
| 0x2002 | Artist Name | UTF-8 string |
| 0x2003 | Album Name | UTF-8 string |
| 0x2004 | Playback State | JSON: {state, position, duration} |
| 0x2005 | Album Art | Chunked base64 (512 bytes/chunk) |
| 0x2006 | Lyrics | LRC format |
how it works
┌──────────────────────────────────────────────┐
│ Android MediaSession API │
│ (Spotify, YouTube Music, Apple Music, etc) │
└───────────────────┬──────────────────────────┘
│ MediaMetadata
│ PlaybackState
│ MediaController
▼
┌──────────────────────────────────────────────┐
│ Janus Service │
│ ┌────────────────────────────────────────┐ │
│ │ MediaSession Listener │ │
│ │ - onMetadataChanged() │ │
│ │ - onPlaybackStateChanged() │ │
│ │ - Extract title/artist/album/art │ │
│ └────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────┐ │
│ │ BLE GATT Server │ │
│ │ - Start advertising │ │
│ │ - Handle characteristic reads │ │
│ │ - Update values on metadata change │ │
│ └────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────┐ │
│ │ Lyrics Fetcher (optional) │ │
│ │ - Query lyrics APIs │ │
│ │ - Parse LRC format │ │
│ │ - Cache results │ │
│ └────────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
│ BLE Advertisement
│ (Name: "Janus")
▼
Mercury (scanning)- 1.android app plays music, updates MediaSession
- 2.janus receives onMetadataChanged notification
- 3.extracts track info, resizes album art, fetches lyrics
- 4.updates GATT characteristic values
- 5.mercury reads characteristics and pushes to redis
building janus
janus is an android app built with gradle. requires android 8.0+ (API 26) for BLE peripheral mode.
# Clone repository
git clone https://github.com/llizardOS/janus
cd janus
# Build debug APK
./gradlew assembleDebug
# Install to connected device
./gradlew installDebug
# Or build release
./gradlew assembleReleaserequired permissions
- •BLUETOOTH - advertise as BLE peripheral
- •BLUETOOTH_ADMIN - start/stop advertising
- •NOTIFICATION_LISTENER - read MediaSession data
- •INTERNET - fetch lyrics (optional)