I'm writing a media player in Python that can play music in connected Bluetooth speakers. I got a speaker with 3 control buttons volume up/down, play/pause. My code (using mpv
) is playing music fine, the volume controls are working too. But I could not get the play/pause button working, here is what I found:
sudo evtest
sees the event:
Testing ... (interrupt to exit)
Event: time 1661208706.167140, type 1 (EV_KEY), code 200 (KEY_PLAYCD), value 1
Event: time 1661208706.167140, -------------- SYN_REPORT ------------
Event: time 1661208706.255603, type 1 (EV_KEY), code 200 (KEY_PLAYCD), value 0
Event: time 1661208706.255603, -------------- SYN_REPORT ------------
sudo btmon
sees them too:
< ACL Data TX: Handle 11 flags 0x00 dlen 12 #2575 [hci0] 124.622157
Channel: 66 len 8 [PSM 23 mode Basic (0x00)] {chan 2}
AVCTP Control: Response: type 0x00 label 2 PID 0x110e
AV/C: Accepted: address 0x48 opcode 0x7c
Subunit: Panel
Opcode: Passthrough
Operation: 0x44 (PLAY Pressed)
Length: 0x00
> ACL Data RX: Handle 11 flags 0x02 dlen 12 #2576 [hci0] 124.623006
Channel: 66 len 8 [PSM 23 mode Basic (0x00)] {chan 2}
AVCTP Control: Command: type 0x00 label 3 PID 0x110e
AV/C: Control: address 0x48 opcode 0x7c
Subunit: Panel
Opcode: Passthrough
Operation: 0xc4 (PLAY Released)
Length: 0x00
dbus-monitor --system
displays the volume change events, but does nothing when I press the "play" button.
How could I catch these events in a python program? I can access dbus events with dbus-python
, but the play event does not get submitted there.
As @ukBaz mentioned the trick is that the play button behaves as a connected keyboard key and their events are not dispatched to the dbus. On my Pi it creates a new device at /dev/input/event1
(but note that its physical address is not the same as the bluetooth address of the connected device. Also its created only after a while BT is connected, maybe when music starts playing?)
From here I can read the events with evdev
with another catch: KEY_PAUSECD
is dispatched if music is playing and KEY_PLAYCD
if not. KEY_PAUSECD
just dispatched once when music is playing. This is the relevant code:
LinuxEventProcessor.thread = threading.Thread(target = LinuxEventProcessor.evdev_handler, name="evdev", daemon=True)
LinuxEventProcessor.thread.start()
def evdev_handler():
# TODO get the right device from the physical address. The issue is that this address does not
# equal the BT device's MAC address.
device = evdev.InputDevice('/dev/input/event1')
for event in device.read_loop():
print("BT input event:", evdev.categorize(event))
if event.type == evdev.ecodes.EV_KEY and event.value == 1:
if event.code == 201: # KEY_PAUSECD. Dispatched only once when music is playing
radio_player.RadioPlayer.stop_radio()
if event.code == 200: # KEY_PLAYCD
radio_player.RadioPlayer.play_radio_if_bt_connected()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.