Reputation: 310
I have a bluetooth headset connected to a linux device. I would like to programmatically receive the play/pause/next/previous/volUp/volDown button press.
After some research I found out that I can interact with Bluez with dbus. I tried to register a MediaPlayer using this script https://github.com/bluez/bluez/blob/master/test/example-player But when I inspect dbus there's no new player, and it doesn't seem to have changed anything.
I also tried to use the Gatt services, but I can't find org.bluez.GattService1 anywhere.
What would be the best way to get the inputs? Is there something wrong with my Bluez?
Background: My goal is to have a audio input and audio output both connected via bluetooth to a rpi. I did manage to do this and have the sound from the input play on the output. Now I would like to forward the inputs too.
Upvotes: 5
Views: 6754
Reputation: 51
I'm late to the party, but the Arch Linux Wiki provides good instructions for this:
https://wiki.archlinux.org/index.php/Bluetooth_headset#Configuration_via_CLI
Install bluez-utils
and run mpris-proxy
. This will forward the commands to the mpris2 interface, where it can be picked up by your media player.
Upvotes: 2
Reputation: 7984
I have looked into this a bit and discovered some things but not reached a full conclusion. I thought I would share it here in the hope that someone can edit/improve the answer.
I have connected up a Bluetooth headset to my Raspberry Pi and DBus interfaces of interest seem to be org.bluez.MediaControl1
and org.bluez.MediaTransport1
(venv) pi@raspberrypi:~/stack_overflow $ busctl tree 'org.bluez'
└─/org
└─/org/bluez
├─/org/bluez/hci0
│ ├─/org/bluez/hci0/dev_74_5C_4B_F8_6D_95
│ │ └─/org/bluez/hci0/dev_74_5C_4B_F8_6D_95/fd2
└─/org/bluez/test
(venv) pi@raspberrypi:~/stack_overflow $ busctl introspect 'org.bluez' '/org/bluez/hci0/dev_74_5C_4B_F8_6D_95'
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
org.bluez.Device1 interface - - -
.CancelPairing method - - -
.Connect method - - -
.ConnectProfile method s - -
.Disconnect method - - -
.DisconnectProfile method s - -
.Pair method - - -
.Adapter property o "/org/bluez/hci0" emits-change
.Address property s "74:5C:4B:F8:6D:95" emits-change
.AddressType property s "public" emits-change
.AdvertisingData property a{yv} - emits-change
.AdvertisingFlags property ay - emits-change
.Alias property s "Jabra Move SE v1.0.0" emits-change writable
.Appearance property q - emits-change
.Blocked property b false emits-change writable
.Class property u 2360324 emits-change
.Connected property b true emits-change
.Icon property s "audio-card" emits-change
.LegacyPairing property b false emits-change
.ManufacturerData property a{qv} - emits-change
.Modalias property s - emits-change
.Name property s "Jabra Move SE v1.0.0" emits-change
.Paired property b true emits-change
.RSSI property n - emits-change
.ServiceData property a{sv} - emits-change
.ServicesResolved property b true emits-change
.Trusted property b false emits-change writable
.TxPower property n - emits-change
.UUIDs property as 5 "00001108-0000-1000-8000-00805f9b34fb… emits-change
org.bluez.MediaControl1 interface - - -
.FastForward method - - deprecated
.Next method - - deprecated
.Pause method - - deprecated
.Play method - - deprecated
.Previous method - - deprecated
.Rewind method - - deprecated
.Stop method - - deprecated
.VolumeDown method - - deprecated
.VolumeUp method - - deprecated
.Connected property b true emits-change
.Player property o - emits-change
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -
(venv) pi@raspberrypi:~/stack_overflow $ busctl introspect 'org.bluez' '/org/bluez/hci0/dev_74_5C_4B_F8_6D_95/fd2'
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
org.bluez.MediaTransport1 interface - - -
.Acquire method - hqq -
.Release method - - -
.TryAcquire method - hqq -
.Codec property y 0 emits-change
.Configuration property ay 4 17 21 2 51 emits-change
.Delay property q - emits-change
.Device property o "/org/bluez/hci0/dev_74_5C_4B_F8_6D_95" emits-change
.State property s "idle" emits-change
.UUID property s "0000110A-0000-1000-8000-00805F9B34FB" emits-change
.Volume property q - emits-change writ
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -
lines 1-19/19 (END)
The org.bluez.MediaControl1
has deprecated next to it and org.bluez.MediaTransport1
is documented at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/media-api.txt#n587
org.bluez.MediaTransport1
has a volume property, but when I try to read it there is an error:
(venv) pi@raspberrypi:~/stack_overflow $ busctl get-property 'org.bluez' '/org/bluez/hci0/dev_74_5C_4B_F8_6D_95/fd2' 'org.bluez.MediaTransport1' Volume
No such property 'Volume'
But I can read other properties fine:
(venv) pi@raspberrypi:~/stack_overflow $ busctl get-property 'org.bluez' '/org/bluez/hci0/dev_74_5C_4B_F8_6D_95/fd2' 'org.bluez.MediaTransport1' State
s "active"
I have been using this bit of code to hold it in the Active
state while I introspect the interfaces.
import os
from gi.repository import GLib
from pydbus import SystemBus
from time import sleep
dev_addr = '74:5C:4B:F8:6D:95'
bluez_service = 'org.bluez'
adapter_path = '/org/bluez/hci0'
device_path = f"{adapter_path}/dev_{dev_addr.replace(':', '_')}"
bus = SystemBus()
mngr = bus.get(bluez_service, '/')
adapter = bus.get(bluez_service, adapter_path)
def get_media_transport_path(dev_path):
mng_objs = mngr.GetManagedObjects()
for dev_objs in mng_objs:
if dev_objs.startswith(dev_path):
state = mng_objs[dev_objs].get('org.bluez.MediaTransport1', {}).get('State', False)
print('State', state)
if state:
return dev_objs
mt_path = get_media_transport_path(device_path)
mt = bus.get(bluez_service, mt_path)
mt_data = mt.Acquire()
print('Acquire', mt_data)
print('GetAll', mt.GetAll('org.bluez.MediaTransport1'))
print('Transport Device', mt.Device)
print('Transport state', mt.State)
sleep(20)
mt.Release()
print('Transport State', mt.State)
My next investigation was going to be around the File Descriptor returned by Acquire
however my DBus library of choice has an issue around fd's https://github.com/LEW21/pydbus/pull/86
Upvotes: 3