Add API to handle playback speed (#3198)
authorAndy Kelk <andy@andykelk.net>
Sat, 21 Feb 2026 23:30:26 +0000 (10:30 +1100)
committerGitHub <noreply@github.com>
Sat, 21 Feb 2026 23:30:26 +0000 (00:30 +0100)
music_assistant/controllers/player_queues.py
music_assistant/helpers/audio.py

index 99795ccabff91c52b015c1e10017621ddb3fcb38..a589a6f2bebf527bb92524b2c2d94b530208e34c 100644 (file)
@@ -389,6 +389,24 @@ class PlayerQueuesController(CoreController):
             if next_item := self.get_next_item(queue_id, queue.index_in_buffer):
                 self._enqueue_next_item(queue_id, next_item)
 
+    @api_command("player_queues/set_playback_speed")
+    async def set_playback_speed(self, queue_id: str, speed: float) -> None:
+        """Set the playback speed for the given queue.
+
+        :param queue_id: queue_id of the queue to configure.
+        :param speed: playback speed multiplier (0.5 to 2.0). 1.0 = normal speed.
+        """
+        if not (0.5 <= speed <= 2.0):
+            raise InvalidDataError(f"Playback speed must be between 0.5 and 2.0, got {speed}")
+        queue = self._queues[queue_id]
+        current_speed = float(queue.extra_attributes.get("playback_speed") or 1.0)
+        if abs(current_speed - speed) < 0.001:
+            return  # no change
+        queue.extra_attributes["playback_speed"] = speed
+        self.signal_update(queue_id)
+        if queue.state == PlaybackState.PLAYING:
+            await self.resume(queue_id)
+
     @api_command("player_queues/play_media")
     async def play_media(
         self,
index 2dd60995171d964ae99ccb18a809affce9cd503c..e44f1d02cdf12a2662d34e56625a47edf64b0330 100644 (file)
@@ -1465,6 +1465,12 @@ def get_player_filter_params(
     elif conf_channels == "right":
         filter_params.append("pan=mono|c0=FR")
 
+    # Apply playback speed via atempo filter if a non-default speed is set on the queue.
+    if _speed_queue := mass.player_queues.get_active_queue(player_id):
+        speed = float(_speed_queue.extra_attributes.get("playback_speed") or 1.0)
+        if speed != 1.0:
+            filter_params.append(f"atempo={speed:.4f}")
+
     # Add safety limiter at the end
     if limiter_enabled:
         filter_params.append("alimiter=limit=-2dB:level=false:asc=true")