A complete Bluetooth audio streaming system for NodeNav that enables:
- Real Bluetooth connectivity with phones
- Audio streaming from phone to computer (A2DP)
- Media playback control via AVRCP protocol
- Live track metadata display
- Play/pause, next, previous controls
-
src/services/bluetooth-audio-service.js(444 lines)- Core Bluetooth audio service
- Handles A2DP audio streaming
- Implements AVRCP media controls
- Platform-specific implementations (Linux fully supported)
- Metadata polling and state management
-
BLUETOOTH_AUDIO_SETUP.md- Complete user documentation
- Platform setup instructions
- Troubleshooting guide
- API reference
-
setup-bluetooth-audio.sh- Automated Linux setup script
- Installs required packages (BlueZ, PulseAudio)
- Configures permissions and services
- Sets up audio routing
-
BLUETOOTH_AUDIO_IMPLEMENTATION.md(this file)- Technical implementation summary
-
src/pages/MediaPlayer.jsx- Replaced simulation with real API calls
- Added automatic device connection on mount
- Implemented state polling from backend
- Connected all controls to Bluetooth API
- Added error handling
-
src/server.js- Added Bluetooth audio service initialization
- Added 8 new API endpoints for media control
- Integrated cleanup for graceful shutdown
-
src/services/api.js- Added 8 new methods in BluetoothAPI class:
connectAudio(address)disconnectAudio()getMediaState()playMedia()pauseMedia()nextTrack()previousTrack()stopMedia()
- Added 8 new methods in BluetoothAPI class:
-
src/App.jsx- Added MediaPlayer import
- Added 'media' route case
- Connected Media card click handler
┌─────────────────────────────────────────────────────────────┐
│ Frontend (React) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ MediaPlayer Component │ │
│ │ - Display track info │ │
│ │ - Playback controls │ │
│ │ - Progress bar │ │
│ └───────────────┬────────────────────────────────────┘ │
│ │ bluetoothAPI │
└──────────────────┼──────────────────────────────────────────┘
│
│ REST API (HTTP)
│
┌──────────────────▼──────────────────────────────────────────┐
│ Backend (Express) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ API Endpoints (server.js) │ │
│ │ /api/bluetooth/audio/connect/:address │ │
│ │ /api/bluetooth/audio/state │ │
│ │ /api/bluetooth/audio/play │ │
│ │ /api/bluetooth/audio/pause │ │
│ │ /api/bluetooth/audio/next │ │
│ │ /api/bluetooth/audio/previous │ │
│ └───────────────┬────────────────────────────────────┘ │
│ │ │
│ ┌───────────────▼────────────────────────────────────┐ │
│ │ Bluetooth Audio Service │ │
│ │ - Device connection management │ │
│ │ - A2DP profile configuration │ │
│ │ - AVRCP command transmission │ │
│ │ - Metadata polling │ │
│ └───────────────┬────────────────────────────────────┘ │
└──────────────────┼──────────────────────────────────────────┘
│
│ System Commands
│
┌──────────────────▼──────────────────────────────────────────┐
│ System Level │
│ │
│ ┌────────────────────────┐ ┌─────────────────────────┐ │
│ │ bluetoothctl │ │ PulseAudio/PipeWire │ │
│ │ (BlueZ D-Bus API) │ │ (Audio Routing) │ │
│ │ - Device pairing │ │ - A2DP sink │ │
│ │ - AVRCP commands │ │ - Audio streaming │ │
│ │ - Metadata retrieval │ │ - Volume control │ │
│ └────────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ Bluetooth Radio
│
┌──────────────────▼──────────────────────────────────────────┐
│ Phone/Device │
│ - Music player (Spotify, Apple Music, etc.) │
│ - Audio source │
│ - AVRCP controller support │
└─────────────────────────────────────────────────────────────┘
-
A2DP (Advanced Audio Distribution Profile)
- Purpose: High-quality audio streaming
- Role: Computer acts as sink (receiver)
- Codec: Typically SBC (SubBand Codec)
- Bitrate: ~320 kbps for high quality
-
AVRCP (Audio/Video Remote Control Profile)
- Purpose: Media control and metadata
- Version: AVRCP 1.5+ for full metadata support
- Commands: Play, Pause, Stop, Next, Previous
- Metadata: Title, Artist, Album, Duration, Position
Connection Flow:
- Device must be paired first (via BluetoothSettings page)
- Backend connects to device using
bluetoothctl connect - System automatically configures A2DP sink profile
- PulseAudio routes audio to default output device
- Metadata polling starts (every 2 seconds)
AVRCP Commands:
# Play
echo "player.play" | bluetoothctl
# Pause
echo "player.pause" | bluetoothctl
# Next
echo "player.next" | bluetoothctl
# Previous
echo "player.previous" | bluetoothctlMetadata Retrieval:
# Get device info including player metadata
echo "info AA:BB:CC:DD:EE:FF" | bluetoothctl | grep -A 20 "Player"Frontend:
- Polls backend every 2 seconds for media state
- Maintains local state for smooth UI
- Handles optimistic updates (updates UI immediately, confirms with backend)
Backend:
- Polls
bluetoothctlevery 2 seconds for metadata - Caches current track information
- Updates position counter when playing
- API failures fallback to local state
- Connection errors are logged but don't crash the app
- Missing metadata gracefully defaults to "Unknown"
- Disconnection automatically stops polling
POST /api/bluetooth/audio/connect/:address
- Connects audio stream to specified device
- Body: none
- Response: { success: true, device: string }
POST /api/bluetooth/audio/disconnect
- Disconnects current audio device
- Body: none
- Response: { success: true }
GET /api/bluetooth/audio/state
- Gets current media playback state
- Response: {
connected: boolean,
device: string,
audioActive: boolean,
isPlaying: boolean,
track: {
title: string,
artist: string,
album: string,
duration: number,
position: number
}
}
POST /api/bluetooth/audio/play
- Sends play command to device
- Response: { success: true, command: "play" }
POST /api/bluetooth/audio/pause
- Sends pause command to device
- Response: { success: true, command: "pause" }
POST /api/bluetooth/audio/next
- Skips to next track
- Response: { success: true, command: "next" }
POST /api/bluetooth/audio/previous
- Goes to previous track
- Response: { success: true, command: "previous" }
POST /api/bluetooth/audio/stop
- Stops playback
- Response: { success: true, command: "stop" }
| Platform | Status | Implementation |
|---|---|---|
| Linux | ✅ Full | bluetoothctl + PulseAudio |
| Windows | Requires native module | |
| macOS | Requires native module |
- BlueZ 5.50+
- PulseAudio 10.0+ or PipeWire 0.3+
- bluez-tools (optional, for advanced features)
- Would need:
windows.devices.bluetoothvia FFI - Or: Native Node.js addon using C++/WinRT
- Would need: IOBluetooth framework via FFI
- Or: Native Node.js addon using Objective-C
- Run setup script:
./setup-bluetooth-audio.sh - Start backend:
cd src && node server.js - Start frontend:
npm run dev - Pair phone via Bluetooth Settings
- Open Media Player
- Play music on phone
The backend includes fallback mock data when no device is connected, allowing development without hardware.
- Latency: 100-300ms typical for Bluetooth audio (acceptable for music)
- Polling Overhead: 2-second intervals minimize CPU usage
- Memory: Minimal, only stores current track info
- Network: Local API calls only (no external services)
- Bluetooth pairing requires user confirmation on both devices
- No authentication tokens stored (uses system Bluetooth stack)
- Audio stream is direct phone → computer (no cloud services)
- Metadata is parsed locally (no external API calls)
- No seeking: AVRCP protocol doesn't support arbitrary position seeking
- No album art: Would require additional AVRCP 1.6+ support
- Single device: Only one audio source at a time
- Platform-specific: Full support currently only on Linux
- Album artwork support (AVRCP 1.6)
- Volume control integration
- Playlist/queue display
- Audio visualizer
- Windows native support
- macOS native support
- Multiple device management
- Bluetooth codec selection (aptX, AAC, LDAC)
- Voice assistant integration
- Podcast-specific features
- Car integration features (steering wheel controls)
- Navigation audio mixing
express- Web servercors- CORS middleware- System:
bluetoothctl,pactl/pipewire
- React 19
- Lucide React (icons)
- Node.js 16+
- Read the setup guide:
BLUETOOTH_AUDIO_SETUP.md - Run the setup script (Linux):
./setup-bluetooth-audio.sh - Start the backend:
node src/server.js - Start the frontend:
npm run dev - Pair your device in Bluetooth Settings
- Navigate to Media Player and enjoy!
- BlueZ project for Linux Bluetooth stack
- PulseAudio/PipeWire for audio routing
- AVRCP specification for media control protocol
Implementation Date: 2025-10-08 Status: Production Ready (Linux), Development (Windows/macOS) License: Same as NodeNav project