Bluetooth: Enable avrcp volume up down
This enables volume up / down command in blueship. The volume change
command in playerctl doesn't work so we directly use D-Bus interface.
For implementation simplicity, this change also SetRemoteAddress when
the device is paired.
BUG=b:438364604
TEST=run test_avrcp_volume_up_down
Change-Id: Ia8a632180c5a802aa7290537831b7d6399562d24
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/chameleon/+/6844397
Reviewed-by: John Lai <[email protected]>
Commit-Queue: Yun-hao Chung <[email protected]>
Tested-by: Yun-hao Chung <[email protected]>
diff --git a/chameleond/bluetooth_grpc/blueship/server/audio.py b/chameleond/bluetooth_grpc/blueship/server/audio.py
index 953c884..a0f163e 100644
--- a/chameleond/bluetooth_grpc/blueship/server/audio.py
+++ b/chameleond/bluetooth_grpc/blueship/server/audio.py
@@ -14,6 +14,10 @@
import grpc
+# Delta of each volume change
+VOLUME_DELTA = 5
+
+
class AudioService(audio_grpc_aio.AudioServicer):
"""Service to trigger Chameleon Audio procedures."""
@@ -97,7 +101,13 @@
request: audio_pb2.SendAvrcpCmdRequest,
context: grpc.ServicerContext,
) -> empty_pb2.Empty:
- if request.cmd == audio_pb2.AUDIO_PLAYER_PLAY:
+ if request.cmd == audio_pb2.AUDIO_PLAYER_VOL_UP:
+ self.ctx.btd.SetVolumeDelta(VOLUME_DELTA)
+ return empty_pb2.Empty()
+ elif request.cmd == audio_pb2.AUDIO_PLAYER_VOL_DOWN:
+ self.ctx.btd.SetVolumeDelta(-VOLUME_DELTA)
+ return empty_pb2.Empty()
+ elif request.cmd == audio_pb2.AUDIO_PLAYER_PLAY:
cmd = "play"
elif request.cmd == audio_pb2.AUDIO_PLAYER_PAUSE:
cmd = "pause"
@@ -107,13 +117,6 @@
cmd = "next"
elif request.cmd == audio_pb2.AUDIO_PLAYER_PREV:
cmd = "prev"
- # For some reason playerctl volume change is not working
- #
- # elif request.cmd == audio_pb2.AUDIO_PLAYER_VOL_UP:
- # cmd = 'volume 0.1+'
- # elif request.cmd == audio_pb2.AUDIO_PLAYER_VOL_DOWN:
- # cmd = 'volume 0.1-'
- #
else:
logging.error("Unrecognized command %s", request.cmd)
return empty_pb2.Empty()
diff --git a/chameleond/bluetooth_grpc/blueship/server/manager.py b/chameleond/bluetooth_grpc/blueship/server/manager.py
index 9dac478..8dc8158 100644
--- a/chameleond/bluetooth_grpc/blueship/server/manager.py
+++ b/chameleond/bluetooth_grpc/blueship/server/manager.py
@@ -130,24 +130,9 @@
return True
- def _check_player_cmd_supported():
- UNSUPPORTED_PLAYER_CMDS = [
- "AUDIO_PLAYER_VOL_UP",
- "AUDIO_PLAYER_VOL_DOWN",
- ]
- for cmd in UNSUPPORTED_PLAYER_CMDS:
- if (
- cmd
- in req_config_dict["audio"]["supportedPlayerCommands"][
- "playerCmdList"
- ]["playerCmdList"]
- ):
- logging.warning("cmd %s is not supported.", cmd)
- return False
-
- return True
-
- check_funcs = [_check_codec_supported, _check_player_cmd_supported]
+ check_funcs = [
+ _check_codec_supported,
+ ]
for func in check_funcs:
try:
diff --git a/chameleond/bluetooth_grpc/blueship/server/power.py b/chameleond/bluetooth_grpc/blueship/server/power.py
index c71a23a..5096c2b 100644
--- a/chameleond/bluetooth_grpc/blueship/server/power.py
+++ b/chameleond/bluetooth_grpc/blueship/server/power.py
@@ -38,7 +38,6 @@
time.sleep(1)
if self.bredr_only and self.connected_device is not None:
- self.ctx.btd.SetRemoteAddress(self.connected_device)
logging.info("Reconnect to %s", self.connected_device)
self.ctx.btd.Connect()
diff --git a/chameleond/bluetooth_grpc/blueship/server/security.py b/chameleond/bluetooth_grpc/blueship/server/security.py
index de38735..a512f06 100644
--- a/chameleond/bluetooth_grpc/blueship/server/security.py
+++ b/chameleond/bluetooth_grpc/blueship/server/security.py
@@ -330,6 +330,7 @@
logging.info(
"Pairing Mode: %s is paired. Stopping pairing mode", address
)
+ self.ctx.btd.SetRemoteAddress(address)
asyncio.run_coroutine_threadsafe(
# Use |None| to indicate pairing is done.
self.pairing_events.put((None, None)),
diff --git a/chameleond/utils/bluetooth_audio.py b/chameleond/utils/bluetooth_audio.py
index b0e8634..1873047 100644
--- a/chameleond/utils/bluetooth_audio.py
+++ b/chameleond/utils/bluetooth_audio.py
@@ -393,6 +393,8 @@
WP_BLUEZ_AAC_CONFIG = "bluez-aac-properties.conf"
WP_BLUEZ_SWB_CONFIG = "bluez-swb-properties.conf"
+ VOLUME_MAX = 127
+
# The pipewire related processes:
# - pipewire: the audio server process
# - wireplumber: an auxiliary process for configuring pipewire
@@ -1810,6 +1812,35 @@
return SystemTools.Output(self.PLAYERCTL, "-p", player, *args).strip()
+ def _GetTransporProperyInterface(self):
+ device_path = self.remote_address.replace(":", "_")
+ path = f"/org/bluez/hci0/dev_{device_path}/fd0"
+
+ obj = self._dbus_system_bus.get_object("org.bluez", path)
+ if obj is None:
+ return None
+ return dbus.Interface(obj, "org.freedesktop.DBus.Properties")
+
+ def SetVolumeDelta(self, volume_delta):
+ """Changes the volume by delta if possible.
+
+ Args:
+ volume_delta: the delta to change.
+ """
+ transport = self._GetTransporProperyInterface()
+ if transport is None:
+ logging.error("Unable to find the audio transport")
+ return
+
+ volume = int(transport.Get("org.bluez.MediaTransport1", "Volume"))
+ new_volume = max(min(volume + volume_delta, self.VOLUME_MAX), 0)
+ logging.debug(f"Setting volume={volume} -> {new_volume}")
+ transport.Set(
+ "org.bluez.MediaTransport1",
+ "Volume",
+ dbus.UInt16(new_volume, variant_level=1),
+ )
+
def SendMediaPlayerCommand(self, command):
"""Execute command towards the given player.