Device management
Unified device enumeration, caching, and matching
One manager enumerates, caches and matches the audio and video hardware. All device access goes through DeviceManager in libmediacore.
Location
src/libs/libmediacore/mediacore/devices/
DeviceManager.hpp / .cpp
DeviceCache.hpp / .cpp
DeviceMatcher.hpp / .cpp
DeviceManager
Singleton providing cached access to all audio and video devices.
Key methods
| Method | Description |
|---|---|
instance() |
Returns the singleton instance |
initializeAudio() |
Initializes audio device enumeration (deferred) |
initializeVideo() |
Initializes video device enumeration (deferred) |
audioInputs() |
Returns cached list of audio input devices |
audioOutputs() |
Returns cached list of audio output devices |
videoInputs() |
Returns cached list of video input devices |
Signals
| Signal | Emitted when |
|---|---|
audioDevicesChanged() |
Audio devices added or removed |
videoDevicesChanged() |
Video devices added or removed |
Deferred initialization
DeviceManager does not enumerate devices at construction time. Calling QMediaDevices::audioOutputs() too early on Linux causes PipeWire to reconfigure the system audio graph, disrupting other applications. Instead:
initializeAudio()is called when the user first enters an audio-consuming contextinitializeVideo()is called when the user first enters a video-consuming context
This split initialization prevents audio enumeration from interfering with video and vice versa.
Warning: Never call
QMediaDevices::audioOutputs()orQMediaDevices::videoInputs()directly. Always go throughDeviceManagerto benefit from caching and deferred initialization.
DeviceCache
TTL-based cache that wraps Qt's QMediaDevices enumeration.
Behavior
- First call enumerates hardware and caches the result
- Subsequent calls within the TTL window return the cached list
- After TTL expiry, the next call re-enumerates
- Hot-plug signals from
QMediaDevicesinvalidate the cache immediately
Configuration
| Property | Default | Description |
|---|---|---|
| TTL | 5000 ms | Cache validity duration |
DeviceMatcher
Finds devices by name, USB vendor:product ID, or fuzzy string similarity.
Match strategies
| Strategy | Description | Use case |
|---|---|---|
Exact |
Exact string match on device description | Known device name |
UsbId |
Match by USB vendor:product ID (e.g., 1234:5678) |
Hardware-specific matching |
Fuzzy |
String similarity with threshold (default 0.5) | Approximate matching |
Smart |
Try exact, then USB ID, then fuzzy | General-purpose lookup |
USB ID extraction
DeviceMatcher extracts USB vendor:product IDs from device description strings using the pattern (xxxx:xxxx):
// Example: "HD Pro Webcam C920 (046d:082d)"
// Extracts: "046d:082d"
auto usbId = DeviceMatcher::extractUsbId(device.description());
Audio-video pairing
DeviceMatcher pairs webcam video inputs with their built-in microphones by matching USB IDs:
auto matcher = DeviceMatcher::usbId(
DeviceMatcher::extractUsbId(videoDevice.description())
);
QAudioDevice pairedMic = matcher.findBest(audioInputList);
Usage examples
Basic device enumeration
auto& dm = media::devices::DeviceManager::instance();
dm.initializeAudio();
for (const auto& device : dm.audioOutputs().devices()) {
qDebug() << device.description();
}
Finding a specific device
auto& dm = media::devices::DeviceManager::instance();
auto matcher = media::devices::DeviceMatcher::smart("USB Webcam");
QCameraDevice camera = matcher.findBest(dm.videoInputs().devices());
Responding to hot-plug
auto& dm = media::devices::DeviceManager::instance();
connect(&dm, &DeviceManager::audioDevicesChanged, this, [&]() {
// Refresh device list in UI
updateDeviceDropdown(dm.audioOutputs().devices());
});
See Also
- Media Architecture - Design rationale
- Graph Framework - Graph-based processing
- Video Streaming - Vision system and streaming