diff --git a/meta-multimedia/recipes-multimedia/pipewire/pipewire/0001-pipewire-compress-offload.patch b/meta-multimedia/recipes-multimedia/pipewire/pipewire/0001-pipewire-compress-offload.patch
new file mode 100644
index 0000000000..9a60e5127a
--- /dev/null
+++ b/meta-multimedia/recipes-multimedia/pipewire/pipewire/0001-pipewire-compress-offload.patch
@@ -0,0 +1,1343 @@
+From 345e4b033c2ff69ab7aa02a123f6041b878f7fb9 Mon Sep 17 00:00:00 2001
+From: Harsh Rai <harsh.rai@oss.qualcomm.com>
+Date: Tue, 16 Jun 2026 19:21:37 +0530
+Subject: [PATCH] pulse: enable MP3 compressed offload via Pulse
+
+Add PipeWire Pulse virtual sink and forwarder for offload.
+Route compressed Pulse streams to PAL compressed sink.
+
+Upstream-Status: Submitted
+
+Signed-off-by: Harsh Rai <harsh.rai@oss.qualcomm.com>
+---
+ src/modules/meson.build                       |   2 +
+ .../module-compress-offload-forwarder.c       | 649 ++++++++++++++++++
+ .../modules/module-compress-offload-sink.c    | 293 ++++++++
+ .../module-protocol-pulse/pulse-server.c      | 254 ++++++-
+ 4 files changed, 1187 insertions(+), 11 deletions(-)
+ create mode 100644 src/modules/module-protocol-pulse/modules/module-compress-offload-forwarder.c
+ create mode 100644 src/modules/module-protocol-pulse/modules/module-compress-offload-sink.c
+
+diff --git a/src/modules/meson.build b/src/modules/meson.build
+index 59f46ae..900871d 100644
+--- a/src/modules/meson.build
++++ b/src/modules/meson.build
+@@ -324,6 +324,8 @@ pipewire_module_protocol_pulse_sources = [
+   'module-protocol-pulse/modules/module-alsa-source.c',
+   'module-protocol-pulse/modules/module-always-sink.c',
+   'module-protocol-pulse/modules/module-combine-sink.c',
++  'module-protocol-pulse/modules/module-compress-offload-sink.c',
++  'module-protocol-pulse/modules/module-compress-offload-forwarder.c',
+   'module-protocol-pulse/modules/module-device-manager.c',
+   'module-protocol-pulse/modules/module-device-restore.c',
+   'module-protocol-pulse/modules/module-echo-cancel.c',
+diff --git a/src/modules/module-protocol-pulse/modules/module-compress-offload-forwarder.c b/src/modules/module-protocol-pulse/modules/module-compress-offload-forwarder.c
+new file mode 100644
+index 0000000..33054e4
+--- /dev/null
++++ b/src/modules/module-protocol-pulse/modules/module-compress-offload-forwarder.c
+@@ -0,0 +1,649 @@
++/* PipeWire */
++/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
++/* SPDX-License-Identifier: BSD-3-Clause-Clear */
++
++#include <errno.h>
++#include <limits.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <spa/param/audio/compressed.h>
++#include <spa/param/audio/format-utils.h>
++#include <spa/param/audio/raw.h>
++#include <spa/utils/result.h>
++#include <spa/utils/string.h>
++#include <pipewire/pipewire.h>
++
++#include "../module.h"
++
++#define NAME "compress-offload-forwarder"
++
++#define DEFAULT_CODEC "mp3"
++#define DEFAULT_RATE 48000u
++#define DEFAULT_CHANNELS 2u
++#define DEFAULT_BITRATE 128000u
++#define DEFAULT_BLOCK_SIZE (16u * 1024u)
++
++static const char *const forwarder_options =
++	"source_sink=<Pulse-visible compress sink node.name> "
++	"target_sink=<PAL compress sink node.name> "
++	"codec=<codec name, default mp3> "
++	"rate=<sample rate, default 48000> "
++	"channels=<number of channels, default 2> "
++	"bitrate=<bit rate, default 128000> "
++	"block_size=<buffer size in bytes, default 16384>";
++
++PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
++#define PW_LOG_TOPIC_DEFAULT mod_topic
++
++struct forwarder_data {
++	struct pw_core *core;
++	struct pw_loop *loop;
++	struct spa_source *activate_event;
++	struct spa_hook core_listener;
++	struct pw_registry *registry;
++	struct spa_hook registry_listener;
++
++	struct pw_stream *capture;
++	struct spa_hook capture_listener;
++	struct pw_stream *playback;
++	struct spa_hook playback_listener;
++
++	char source_name[256];
++	char monitor_name[280];
++	char target_name[256];
++	char codec[32];
++	uint32_t rate;
++	uint32_t channels;
++	uint32_t bitrate;
++	uint32_t block_size;
++	uint32_t target_id;
++	uint8_t *pending_data;
++	uint32_t pending_size;
++	uint32_t pending_offset;
++	uint8_t capture_streaming:1;
++	uint8_t logged_first_buffer:1;
++	uint8_t logged_first_output_buffer:1;
++	uint8_t logged_silence_buffer:1;
++	uint8_t activate_pending:1;
++	uint8_t playback_active:1;
++	uint8_t playback_failed:1;
++};
++
++static int create_playback_stream(struct forwarder_data *d);
++static void set_playback_active(struct forwarder_data *d, bool active);
++static void maybe_create_playback_stream(struct forwarder_data *d, const char *reason);
++
++static void request_playback_activation(struct forwarder_data *d)
++{
++	if (d->activate_event == NULL || d->activate_pending)
++		return;
++	d->activate_pending = true;
++	pw_loop_signal_event(d->loop, d->activate_event);
++}
++
++static void playback_activate_event(void *data, uint64_t count)
++{
++	struct forwarder_data *d = data;
++
++	d->activate_pending = false;
++	maybe_create_playback_stream(d, "first-audio-buffer");
++}
++
++static bool buffer_is_zeroed(const void *data, uint32_t size)
++{
++	const uint8_t *bytes = data;
++	uint32_t index;
++
++	for (index = 0; index < size; index++) {
++		if (bytes[index] != 0)
++			return false;
++	}
++	return true;
++}
++
++static void clear_pending_data(struct forwarder_data *d)
++{
++	free(d->pending_data);
++	d->pending_data = NULL;
++	d->pending_size = 0;
++	d->pending_offset = 0;
++}
++
++static void compact_pending_data(struct forwarder_data *d)
++{
++	uint32_t remaining;
++
++	if (d->pending_offset == 0)
++		return;
++	if (d->pending_offset >= d->pending_size) {
++		clear_pending_data(d);
++		return;
++	}
++	remaining = d->pending_size - d->pending_offset;
++	memmove(d->pending_data, d->pending_data + d->pending_offset, remaining);
++	d->pending_size = remaining;
++	d->pending_offset = 0;
++}
++
++static int append_pending_data(struct forwarder_data *d, const void *data, uint32_t size)
++{
++	uint8_t *pending_data;
++
++	if (size == 0)
++		return 0;
++	compact_pending_data(d);
++	if (d->pending_size > UINT32_MAX - size)
++		return -EOVERFLOW;
++	pending_data = realloc(d->pending_data, d->pending_size + size);
++	if (pending_data == NULL)
++		return -errno;
++	d->pending_data = pending_data;
++	memcpy(d->pending_data + d->pending_size, data, size);
++	d->pending_size += size;
++	return 0;
++}
++
++static void maybe_create_playback_stream(struct forwarder_data *d, const char *reason)
++{
++	int res;
++
++	if (!d->capture_streaming)
++		return;
++	if (d->playback != NULL) {
++		set_playback_active(d, true);
++		return;
++	}
++	if (d->target_id == PW_ID_ANY) {
++		pw_log_debug("compress-forwarder target:%s not resolved yet, defer output create (%s)",
++				d->target_name, reason);
++		return;
++	}
++	res = create_playback_stream(d);
++	if (res < 0)
++		pw_log_error("compress-forwarder target:%s create failed (%s): %s",
++				d->target_name, reason, spa_strerror(res));
++	else
++		set_playback_active(d, true);
++}
++
++static void destroy_playback_stream(struct forwarder_data *d)
++{
++	clear_pending_data(d);
++	if (d->playback == NULL)
++		return;
++	spa_hook_remove(&d->playback_listener);
++	pw_stream_destroy(d->playback);
++	d->playback = NULL;
++	d->playback_active = false;
++	d->playback_failed = false;
++}
++
++static const struct spa_pod *build_raw_format(struct forwarder_data *d,
++		struct spa_pod_builder *builder, uint32_t id)
++{
++	struct spa_audio_info_raw info;
++
++	spa_zero(info);
++	info.format = SPA_AUDIO_FORMAT_S16_LE;
++	info.rate = d->rate;
++	info.channels = d->channels;
++	if (info.channels == 1) {
++		info.position[0] = SPA_AUDIO_CHANNEL_MONO;
++	} else {
++		info.channels = 2;
++		info.position[0] = SPA_AUDIO_CHANNEL_FL;
++		info.position[1] = SPA_AUDIO_CHANNEL_FR;
++	}
++	return spa_format_audio_raw_build(builder, id, &info);
++}
++
++static const struct spa_pod *build_encoded_format(struct forwarder_data *d,
++		struct spa_pod_builder *builder, uint32_t id)
++{
++	struct spa_audio_info info;
++
++	spa_zero(info);
++	info.media_type = SPA_MEDIA_TYPE_audio;
++	info.media_subtype = SPA_MEDIA_SUBTYPE_mp3;
++	info.info.mp3.rate = d->rate;
++	info.info.mp3.channels = d->channels;
++	info.info.mp3.channel_mode = d->channels == 1 ?
++		SPA_AUDIO_MP3_CHANNEL_MODE_MONO : SPA_AUDIO_MP3_CHANNEL_MODE_STEREO;
++
++	return spa_format_audio_build(builder, id, &info);
++}
++
++static void playback_state_changed(void *data, enum pw_stream_state old,
++		enum pw_stream_state state, const char *error)
++{
++	struct forwarder_data *d = data;
++
++	pw_log_debug("compress-forwarder target:%s state %d -> %d%s%s",
++			d->target_name, old, state, error ? ": " : "", error ? error : "");
++	if (state == PW_STREAM_STATE_ERROR)
++		d->playback_failed = true;
++}
++
++static void set_playback_active(struct forwarder_data *d, bool active)
++{
++	if (d->playback == NULL || d->playback_active == active)
++		return;
++	pw_log_debug("compress-forwarder target:%s active=%d", d->target_name, active);
++	pw_stream_set_active(d->playback, active);
++	d->playback_active = active;
++}
++
++static void capture_state_changed(void *data, enum pw_stream_state old,
++		enum pw_stream_state state, const char *error)
++{
++	struct forwarder_data *d = data;
++
++	pw_log_debug("compress-forwarder source:%s state %d -> %d%s%s",
++			d->monitor_name, old, state, error ? ": " : "", error ? error : "");
++	if (d->playback_failed)
++		destroy_playback_stream(d);
++	d->capture_streaming = state == PW_STREAM_STATE_STREAMING;
++	if (state == PW_STREAM_STATE_PAUSED || state == PW_STREAM_STATE_ERROR)
++		set_playback_active(d, false);
++}
++
++static void capture_process(void *data)
++{
++	struct forwarder_data *d = data;
++	struct pw_buffer *in_buf, *out_buf;
++	struct spa_data *in_data, *out_data;
++	uint32_t in_offset, in_size, out_size, copy_size;
++	const void *input_data;
++	const void *copy_data;
++	uint32_t copy_available;
++	int res;
++
++	in_buf = pw_stream_dequeue_buffer(d->capture);
++	if (in_buf == NULL)
++		return;
++
++	in_data = &in_buf->buffer->datas[0];
++	if (in_data->data == NULL || in_data->chunk == NULL) {
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++	in_offset = SPA_MIN(in_data->chunk->offset, in_data->maxsize);
++	in_size = SPA_MIN(in_data->chunk->size, in_data->maxsize - in_offset);
++	input_data = SPA_PTROFF(in_data->data, in_offset, void);
++	if (in_size == 0) {
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++	if (buffer_is_zeroed(input_data, in_size)) {
++		if (!d->logged_silence_buffer) {
++			pw_log_debug("compress-forwarder source:%s ignoring zeroed startup buffer size=%u flags=0x%x",
++					d->monitor_name, in_size, in_data->chunk->flags);
++			d->logged_silence_buffer = true;
++		}
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++	if (!d->logged_first_buffer) {
++		const uint8_t *bytes = SPA_PTROFF(in_data->data, in_offset, const uint8_t);
++		pw_log_debug("compress-forwarder source:%s first non-silence buffer size=%u offset=%u flags=0x%x",
++				d->monitor_name, in_size, in_offset, in_data->chunk->flags);
++		pw_log_debug("compress-forwarder source:%s first non-silence bytes=%02x %02x %02x %02x %02x %02x %02x %02x",
++				d->monitor_name,
++				in_size > 0 ? bytes[0] : 0,
++				in_size > 1 ? bytes[1] : 0,
++				in_size > 2 ? bytes[2] : 0,
++				in_size > 3 ? bytes[3] : 0,
++				in_size > 4 ? bytes[4] : 0,
++				in_size > 5 ? bytes[5] : 0,
++				in_size > 6 ? bytes[6] : 0,
++				in_size > 7 ? bytes[7] : 0);
++		d->logged_first_buffer = true;
++	}
++
++	if (d->playback_failed)
++		destroy_playback_stream(d);
++
++	res = append_pending_data(d, input_data, in_size);
++	if (res < 0) {
++		pw_log_error("compress-forwarder source:%s failed to preserve input before target write: %s",
++				d->monitor_name, spa_strerror(res));
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++
++	if (d->playback == NULL) {
++		request_playback_activation(d);
++		if (d->playback == NULL) {
++			pw_log_debug("compress-forwarder source:%s preserved %u bytes pending target create total=%u",
++					d->monitor_name, in_size, d->pending_size - d->pending_offset);
++			pw_stream_queue_buffer(d->capture, in_buf);
++			return;
++		}
++	}
++	if (!d->playback_active)
++		set_playback_active(d, true);
++	if (d->playback_failed || !d->playback_active) {
++		pw_log_debug("compress-forwarder source:%s preserved %u bytes pending inactive target total=%u",
++				d->monitor_name, in_size, d->pending_size - d->pending_offset);
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++
++	out_buf = pw_stream_dequeue_buffer(d->playback);
++	if (out_buf == NULL) {
++		pw_log_debug("compress-forwarder source:%s preserved %u bytes pending output buffer total=%u",
++				d->monitor_name, in_size, d->pending_size - d->pending_offset);
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++
++	out_data = &out_buf->buffer->datas[0];
++	if (out_data->data == NULL || out_data->chunk == NULL) {
++		pw_stream_queue_buffer(d->playback, out_buf);
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++
++	out_size = out_data->maxsize;
++	if (out_size == 0) {
++		pw_stream_queue_buffer(d->playback, out_buf);
++		pw_stream_queue_buffer(d->capture, in_buf);
++		return;
++	}
++	copy_data = d->pending_data + d->pending_offset;
++	copy_available = d->pending_size - d->pending_offset;
++	copy_size = SPA_MIN(copy_available, out_size);
++	memcpy(out_data->data, copy_data, copy_size);
++	d->pending_offset += copy_size;
++	if (d->pending_offset >= d->pending_size)
++		clear_pending_data(d);
++
++	out_data->chunk->offset = 0;
++	out_data->chunk->size = copy_size;
++	out_data->chunk->stride = 1;
++	out_buf->size = copy_size;
++
++	if (!d->logged_first_output_buffer) {
++		const uint8_t *out_bytes = out_data->data;
++		pw_log_debug("compress-forwarder target:%s queue buffer copy_size=%u out_max=%u chunk=%u/%u/%d bytes=%02x %02x %02x %02x %02x %02x %02x %02x",
++				d->target_name, copy_size, out_data->maxsize,
++				out_data->chunk->offset, out_data->chunk->size,
++				out_data->chunk->stride,
++				copy_size > 0 ? out_bytes[0] : 0,
++				copy_size > 1 ? out_bytes[1] : 0,
++				copy_size > 2 ? out_bytes[2] : 0,
++				copy_size > 3 ? out_bytes[3] : 0,
++				copy_size > 4 ? out_bytes[4] : 0,
++				copy_size > 5 ? out_bytes[5] : 0,
++				copy_size > 6 ? out_bytes[6] : 0,
++				copy_size > 7 ? out_bytes[7] : 0);
++		d->logged_first_output_buffer = true;
++	}
++
++	pw_stream_queue_buffer(d->playback, out_buf);
++	pw_stream_queue_buffer(d->capture, in_buf);
++}
++
++static const struct pw_stream_events capture_events = {
++	PW_VERSION_STREAM_EVENTS,
++	.state_changed = capture_state_changed,
++	.process = capture_process,
++};
++
++static const struct pw_stream_events playback_events = {
++	PW_VERSION_STREAM_EVENTS,
++	.state_changed = playback_state_changed,
++};
++
++static void registry_global(void *data, uint32_t id, uint32_t permissions,
++		const char *type, uint32_t version, const struct spa_dict *props)
++{
++	struct forwarder_data *d = data;
++	const char *name;
++
++	if (!spa_streq(type, PW_TYPE_INTERFACE_Node) || props == NULL)
++		return;
++	name = spa_dict_lookup(props, PW_KEY_NODE_NAME);
++	if (!spa_streq(name, d->target_name))
++		return;
++	d->target_id = id;
++	pw_log_info("compress-forwarder target:%s resolved id=%u", d->target_name, id);
++}
++
++static void registry_global_remove(void *data, uint32_t id)
++{
++	struct forwarder_data *d = data;
++
++	if (id != d->target_id)
++		return;
++	pw_log_info("compress-forwarder target:%s removed id=%u", d->target_name, id);
++	d->target_id = PW_ID_ANY;
++	destroy_playback_stream(d);
++}
++
++static const struct pw_registry_events registry_events = {
++	PW_VERSION_REGISTRY_EVENTS,
++	.global = registry_global,
++	.global_remove = registry_global_remove,
++};
++
++static int create_playback_stream(struct forwarder_data *d)
++{
++	struct pw_properties *props;
++	const struct spa_pod *params[2];
++	uint8_t buffer[1024];
++	struct spa_pod_builder builder;
++	uint32_t n_params = 0;
++	int res;
++
++	props = pw_properties_new(PW_KEY_MEDIA_CLASS, "Stream/Output/Audio",
++			PW_KEY_NODE_NAME, "compress-offload-forwarder-output",
++			PW_KEY_MEDIA_TYPE, "Audio",
++			PW_KEY_MEDIA_CATEGORY, "Playback",
++			PW_KEY_MEDIA_ROLE, "Music",
++			PW_KEY_TARGET_OBJECT, d->target_name,
++			PW_KEY_NODE_AUTOCONNECT, "true",
++			PW_KEY_STREAM_DONT_REMIX, "true",
++			"node.dont-reconnect", "true",
++			PW_KEY_NODE_RATE, "1/48000",
++			"compress.offload", "true",
++			"codec.type", d->codec,
++			NULL);
++	if (props == NULL)
++		return -errno;
++	pw_properties_setf(props, "codec.sample_rate", "%u", d->rate);
++	pw_properties_setf(props, "codec.channels", "%u", d->channels);
++	pw_properties_setf(props, "codec.bit_rate", "%u", d->bitrate);
++	pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", d->rate);
++
++	d->playback = pw_stream_new(d->core, "compress offload forwarder output", props);
++	if (d->playback == NULL)
++		return -errno;
++	pw_stream_add_listener(d->playback, &d->playback_listener, &playback_events, d);
++
++	spa_pod_builder_init(&builder, buffer, sizeof(buffer));
++	params[n_params++] = build_encoded_format(d, &builder, SPA_PARAM_EnumFormat);
++	pw_log_debug("compress-forwarder target:%s connect target-id=%u", d->target_name, d->target_id);
++	res = pw_stream_connect(d->playback, PW_DIRECTION_OUTPUT, d->target_id,
++			PW_STREAM_FLAG_AUTOCONNECT |
++			PW_STREAM_FLAG_NO_CONVERT |
++			PW_STREAM_FLAG_MAP_BUFFERS |
++			PW_STREAM_FLAG_RT_PROCESS,
++			params, n_params);
++	if (res < 0) {
++		destroy_playback_stream(d);
++		return res;
++	}
++	pw_stream_set_active(d->playback, false);
++	d->playback_active = false;
++	d->playback_failed = false;
++	return 0;
++}
++
++static int create_capture_stream(struct forwarder_data *d)
++{
++	struct pw_properties *props;
++	const struct spa_pod *params[2];
++	uint8_t buffer[1024];
++	struct spa_pod_builder builder;
++	uint32_t n_params = 0;
++	int res;
++
++	props = pw_properties_new(PW_KEY_MEDIA_CLASS, "Stream/Input/Audio",
++			PW_KEY_NODE_NAME, "compress-offload-forwarder-capture",
++			PW_KEY_TARGET_OBJECT, d->source_name,
++			PW_KEY_NODE_AUTOCONNECT, "true",
++			PW_KEY_STREAM_CAPTURE_SINK, "true",
++			PW_KEY_STREAM_DONT_REMIX, "true",
++			"node.dont-reconnect", "true",
++			NULL);
++	if (props == NULL)
++		return -errno;
++	pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", d->rate);
++
++	d->capture = pw_stream_new(d->core, "compress offload forwarder capture", props);
++	if (d->capture == NULL)
++		return -errno;
++	pw_stream_add_listener(d->capture, &d->capture_listener, &capture_events, d);
++
++	spa_pod_builder_init(&builder, buffer, sizeof(buffer));
++	params[n_params++] = build_raw_format(d, &builder, SPA_PARAM_EnumFormat);
++	res = pw_stream_connect(d->capture, PW_DIRECTION_INPUT, PW_ID_ANY,
++			PW_STREAM_FLAG_AUTOCONNECT |
++			PW_STREAM_FLAG_MAP_BUFFERS |
++			PW_STREAM_FLAG_RT_PROCESS,
++			params, n_params);
++	if (res < 0)
++		return res;
++	pw_stream_set_active(d->capture, true);
++	return 0;
++}
++
++static void core_error(void *data, uint32_t id, int seq, int res, const char *message)
++{
++	struct module *module = data;
++
++	pw_log_error("compress-forwarder error id:%u seq:%d res:%d (%s): %s",
++			id, seq, res, spa_strerror(res), message);
++	if (id == PW_ID_CORE && res == -EPIPE)
++		module_schedule_unload(module);
++}
++
++static const struct pw_core_events core_events = {
++	PW_VERSION_CORE_EVENTS,
++	.error = core_error,
++};
++
++static int module_compress_offload_forwarder_load(struct module *module)
++{
++	struct forwarder_data *d = module->user_data;
++	int res;
++
++	PW_LOG_TOPIC_INIT(mod_topic);
++	d->loop = pw_context_get_main_loop(module->impl->context);
++	if (d->loop == NULL)
++		return -EINVAL;
++	d->activate_event = pw_loop_add_event(d->loop, playback_activate_event, d);
++	if (d->activate_event == NULL)
++		return -errno;
++	d->core = pw_context_connect(module->impl->context, NULL, 0);
++	if (d->core == NULL)
++		return -errno;
++	pw_core_add_listener(d->core, &d->core_listener, &core_events, module);
++	d->target_id = PW_ID_ANY;
++	d->registry = pw_core_get_registry(d->core, PW_VERSION_REGISTRY, 0);
++	if (d->registry == NULL)
++		return -errno;
++	pw_registry_add_listener(d->registry, &d->registry_listener, &registry_events, d);
++
++	res = create_capture_stream(d);
++	if (res < 0)
++		return res;
++
++	pw_log_info("compress-forwarder loaded: source=%s monitor=%s target=%s codec=%s rate=%u channels=%u",
++			d->source_name, d->monitor_name, d->target_name,
++			d->codec, d->rate, d->channels);
++	module_emit_loaded(module, 0);
++	return 0;
++}
++
++static int module_compress_offload_forwarder_unload(struct module *module)
++{
++	struct forwarder_data *d = module->user_data;
++
++	if (d->capture != NULL) {
++		spa_hook_remove(&d->capture_listener);
++		pw_stream_destroy(d->capture);
++		d->capture = NULL;
++	}
++	destroy_playback_stream(d);
++	if (d->registry != NULL) {
++		spa_hook_remove(&d->registry_listener);
++		pw_proxy_destroy((struct pw_proxy*)d->registry);
++		d->registry = NULL;
++	}
++	if (d->core != NULL) {
++		spa_hook_remove(&d->core_listener);
++		pw_core_disconnect(d->core);
++		d->core = NULL;
++	}
++	if (d->activate_event != NULL) {
++		pw_loop_destroy_source(d->loop, d->activate_event);
++		d->activate_event = NULL;
++	}
++	d->loop = NULL;
++	return 0;
++}
++
++static int module_compress_offload_forwarder_prepare(struct module *module)
++{
++	struct forwarder_data *d = module->user_data;
++	struct pw_properties *props = module->props;
++	const char *str;
++
++	PW_LOG_TOPIC_INIT(mod_topic);
++	str = pw_properties_get(props, "source_sink");
++	spa_scnprintf(d->source_name, sizeof(d->source_name), "%s",
++			str ? str : "pal_speaker_compress");
++	str = pw_properties_get(props, "target_sink");
++	spa_scnprintf(d->target_name, sizeof(d->target_name), "%s",
++			str ? str : "pal_sink_speaker_compress");
++	str = pw_properties_get(props, "codec");
++	spa_scnprintf(d->codec, sizeof(d->codec), "%s", str ? str : DEFAULT_CODEC);
++	d->rate = pw_properties_get_uint32(props, "rate", DEFAULT_RATE);
++	d->channels = pw_properties_get_uint32(props, "channels", DEFAULT_CHANNELS);
++	d->bitrate = pw_properties_get_uint32(props, "bitrate", DEFAULT_BITRATE);
++	d->block_size = pw_properties_get_uint32(props, "block_size", DEFAULT_BLOCK_SIZE);
++	spa_scnprintf(d->monitor_name, sizeof(d->monitor_name), "%s.monitor", d->source_name);
++
++	if (!spa_streq(d->codec, "mp3")) {
++		pw_log_warn("compress-forwarder only supports mp3 right now, requested codec=%s", d->codec);
++		return -ENOTSUP;
++	}
++	if (d->channels == 0)
++		d->channels = DEFAULT_CHANNELS;
++	if (d->rate == 0)
++		d->rate = DEFAULT_RATE;
++	if (d->block_size == 0)
++		d->block_size = DEFAULT_BLOCK_SIZE;
++
++	return 0;
++}
++
++static const struct spa_dict_item module_compress_offload_forwarder_info[] = {
++	{ PW_KEY_MODULE_AUTHOR,      "Qualcomm Technologies, Inc." },
++	{ PW_KEY_MODULE_DESCRIPTION, "Forward Pulse compress-offload sink data to PAL compress sink" },
++	{ PW_KEY_MODULE_USAGE,       forwarder_options },
++	{ PW_KEY_MODULE_VERSION,     PACKAGE_VERSION },
++};
++
++DEFINE_MODULE_INFO(module_compress_offload_forwarder) = {
++	.name       = "module-compress-offload-forwarder",
++	.prepare    = module_compress_offload_forwarder_prepare,
++	.load       = module_compress_offload_forwarder_load,
++	.unload     = module_compress_offload_forwarder_unload,
++	.properties = &SPA_DICT_INIT_ARRAY(module_compress_offload_forwarder_info),
++	.data_size  = sizeof(struct forwarder_data),
++};
+diff --git a/src/modules/module-protocol-pulse/modules/module-compress-offload-sink.c b/src/modules/module-protocol-pulse/modules/module-compress-offload-sink.c
+new file mode 100644
+index 0000000..243cc8e
+--- /dev/null
++++ b/src/modules/module-protocol-pulse/modules/module-compress-offload-sink.c
+@@ -0,0 +1,293 @@
++/* PipeWire */
++/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
++/* SPDX-License-Identifier: BSD-3-Clause-Clear */
++
++#include <errno.h>
++#include <stdlib.h>
++
++#include <spa/utils/result.h>
++#include <pipewire/pipewire.h>
++
++#include "../module.h"
++
++static const char *const pulse_module_options =
++	"sink_name=<name of sink> "
++	"sink_properties=<properties for the sink> "
++	"target_sink=<node.name of the downstream compress-offload sink> "
++	"codec=<codec name, default mp3> "
++	"rate=<sample rate, default 44100> "
++	"channels=<number of channels, default 2> "
++	"bitrate=<bit rate, default 128000>";
++
++#define NAME "compress-offload-sink"
++
++PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
++#define PW_LOG_TOPIC_DEFAULT mod_topic
++
++struct module_compress_offload_sink_data {
++	struct pw_core *core;
++	struct spa_hook core_listener;
++
++	struct pw_proxy *proxy;
++	struct spa_hook proxy_listener;
++};
++
++static void module_proxy_removed(void *data)
++{
++	struct module *module = data;
++	struct module_compress_offload_sink_data *d = module->user_data;
++
++	pw_log_debug("compress-forwarder proxy removed: proxy=%p", d->proxy);
++	pw_proxy_destroy(d->proxy);
++}
++
++static void module_proxy_destroy(void *data)
++{
++	struct module *module = data;
++	struct module_compress_offload_sink_data *d = module->user_data;
++
++	pw_log_debug("compress-forwarder proxy destroy: proxy=%p - scheduling module unload", d->proxy);
++	spa_hook_remove(&d->proxy_listener);
++	d->proxy = NULL;
++	module_schedule_unload(module);
++}
++
++static void module_proxy_bound_props(void *data, uint32_t global_id, const struct spa_dict *props)
++{
++	struct module *module = data;
++	struct module_compress_offload_sink_data *d = module->user_data;
++
++	pw_log_debug("proxy %p bound id:%u module_index=%u", d->proxy, global_id, module->index);
++	pw_log_debug("compress-forwarder node successfully created and bound, emitting loaded");
++	module_emit_loaded(module, 0);
++}
++
++static void module_proxy_error(void *data, int seq, int res, const char *message)
++{
++	struct module *module = data;
++	struct module_compress_offload_sink_data *d = module->user_data;
++
++	pw_log_error("proxy %p error %d: %s", d->proxy, res, message);
++	pw_proxy_destroy(d->proxy);
++}
++
++static const struct pw_proxy_events proxy_events = {
++	PW_VERSION_PROXY_EVENTS,
++	.removed      = module_proxy_removed,
++	.bound_props  = module_proxy_bound_props,
++	.error        = module_proxy_error,
++	.destroy      = module_proxy_destroy,
++};
++
++static void module_core_error(void *data, uint32_t id, int seq, int res, const char *message)
++{
++	struct module *module = data;
++
++	pw_log_error("error id:%u seq:%d res:%d (%s): %s",
++			id, seq, res, spa_strerror(res), message);
++
++	if (id == PW_ID_CORE && res == -EPIPE)
++		module_schedule_unload(module);
++}
++
++static const struct pw_core_events core_events = {
++	PW_VERSION_CORE_EVENTS,
++	.error = module_core_error,
++};
++
++static int module_compress_offload_sink_load(struct module *module)
++{
++	struct module_compress_offload_sink_data *d = module->user_data;
++
++	pw_log_info("compress-forwarder load: node=%s target=%s codec=%s rate=%s channels=%s bitrate=%s",
++			pw_properties_get(module->props, PW_KEY_NODE_NAME),
++			pw_properties_get(module->props, "compress.target.object"),
++			pw_properties_get(module->props, "codec.type"),
++			pw_properties_get(module->props, "codec.sample_rate"),
++			pw_properties_get(module->props, "codec.channels"),
++			pw_properties_get(module->props, "codec.bit_rate"));
++
++	d->core = pw_context_connect(module->impl->context, NULL, 0);
++	if (d->core == NULL) {
++		pw_log_error("compress-forwarder core connect failed: errno=%d (%s)",
++				errno, spa_strerror(-errno));
++		return -errno;
++	}
++
++	pw_log_debug("compress-forwarder core connected: core=%p", d->core);
++	pw_core_add_listener(d->core, &d->core_listener, &core_events, module);
++	pw_properties_setf(module->props, "pulse.module.id", "%u", module->index);
++
++	d->proxy = pw_core_create_object(d->core,
++					 "adapter", PW_TYPE_INTERFACE_Node, PW_VERSION_NODE,
++					 module->props ? &module->props->dict : NULL, 0);
++	if (d->proxy == NULL) {
++		pw_log_error("compress-forwarder adapter create failed: errno=%d (%s)",
++				errno, spa_strerror(-errno));
++		return -errno;
++	}
++
++	pw_log_debug("compress-forwarder adapter create requested: proxy=%p - waiting for bound_props", d->proxy);
++	pw_proxy_add_listener(d->proxy, &d->proxy_listener, &proxy_events, module);
++	return SPA_RESULT_RETURN_ASYNC(0);
++}
++
++static int module_compress_offload_sink_unload(struct module *module)
++{
++	struct module_compress_offload_sink_data *d = module->user_data;
++
++	pw_log_debug("compress-forwarder unload: proxy=%p core=%p - cleaning up", d->proxy, d->core);
++	if (d->proxy != NULL) {
++		spa_hook_remove(&d->proxy_listener);
++		pw_proxy_destroy(d->proxy);
++		d->proxy = NULL;
++	}
++	if (d->core != NULL) {
++		spa_hook_remove(&d->core_listener);
++		pw_core_disconnect(d->core);
++		d->core = NULL;
++	}
++	return 0;
++}
++
++static int module_compress_offload_sink_prepare(struct module * const module)
++{
++	struct pw_properties * const props = module->props;
++	const char *str;
++	uint32_t rate = 44100;
++	uint32_t channels = 2;
++	uint32_t bitrate = 128000;
++
++	PW_LOG_TOPIC_INIT(mod_topic);
++
++	if ((str = pw_properties_get(props, "sink_name")) != NULL) {
++		pw_log_debug("compress-forwarder option: sink_name=%s", str);
++		pw_properties_set(props, PW_KEY_NODE_NAME, str);
++		pw_properties_set(props, "sink_name", NULL);
++	} else {
++		pw_log_debug("compress-forwarder option: sink_name missing, using default");
++		pw_properties_set(props, PW_KEY_NODE_NAME, "compress-offload-sink");
++	}
++
++	if ((str = pw_properties_get(props, "sink_properties")) != NULL) {
++		pw_log_debug("compress-forwarder option: sink_properties=%s", str);
++		module_args_add_props(props, str);
++		pw_properties_set(props, "sink_properties", NULL);
++	}
++
++	if ((str = pw_properties_get(props, "target_sink")) != NULL) {
++		pw_log_debug("compress-forwarder option: target_sink=%s", str);
++		pw_properties_set(props, "compress.target.object", str);
++		pw_properties_set(props, "target_sink", NULL);
++	} else {
++		pw_log_warn("compress-forwarder option: target_sink missing; stream will not have explicit compress target");
++	}
++
++	if ((str = pw_properties_get(props, "rate")) != NULL) {
++		uint32_t v = (uint32_t)atoi(str);
++		if (v > 0)
++			rate = v;
++		pw_properties_set(props, "rate", NULL);
++	}
++	if ((str = pw_properties_get(props, "channels")) != NULL) {
++		uint32_t v = (uint32_t)atoi(str);
++		if (v > 0)
++			channels = v;
++		pw_properties_set(props, "channels", NULL);
++	}
++	if ((str = pw_properties_get(props, "bitrate")) != NULL) {
++		uint32_t v = (uint32_t)atoi(str);
++		if (v > 0)
++			bitrate = v;
++		pw_properties_set(props, "bitrate", NULL);
++	}
++	if ((str = pw_properties_get(props, "channel_map")) != NULL) {
++		pw_properties_set(props, "audio.position", str);
++		pw_properties_set(props, "channel_map", NULL);
++	} else {
++		switch (channels) {
++		case 1:
++			pw_properties_set(props, "audio.position", "[ MONO ]");
++			break;
++		case 2:
++			pw_properties_set(props, "audio.position", "[ FL FR ]");
++			break;
++		case 3:
++			pw_properties_set(props, "audio.position", "[ FL FR LFE ]");
++			break;
++		case 4:
++			pw_properties_set(props, "audio.position", "[ FL FR RL RR ]");
++			break;
++		case 5:
++			pw_properties_set(props, "audio.position", "[ FL FR FC RL RR ]");
++			break;
++		case 6:
++			pw_properties_set(props, "audio.position", "[ FL FR FC LFE RL RR ]");
++			break;
++		case 8:
++			pw_properties_set(props, "audio.position", "[ FL FR FC LFE RL RR SL SR ]");
++			break;
++		default:
++			break;
++		}
++	}
++
++	str = pw_properties_get(props, "codec");
++	pw_properties_set(props, "codec.type", str ? str : "mp3");
++	pw_properties_setf(props, "codec.sample_rate", "%u", rate);
++	pw_properties_setf(props, "codec.channels",    "%u", channels);
++	pw_properties_setf(props, "codec.bit_rate",    "%u", bitrate);
++	pw_properties_set(props, "codec", NULL);
++
++	if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL)
++		pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink");
++	if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
++		pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s (compress offload)",
++				pw_properties_get(props, PW_KEY_NODE_NAME));
++
++	/*
++	 * Advertise this node as an encoded-only sink so WirePlumber's
++	 * canPassthrough() allows linking compress streams to it.
++	 * audio.format=S16LE is kept as the synthetic PCM sample_spec that
++	 * Pulse clients see in pactl; no PCM conversion ever occurs.
++	 */
++	pw_properties_set(props, PW_KEY_AUDIO_FORMAT,                "S16LE");
++	pw_properties_setf(props, PW_KEY_AUDIO_RATE,                 "%u", rate);
++	pw_properties_setf(props, PW_KEY_AUDIO_CHANNELS,             "%u", channels);
++	pw_properties_set(props, "item.node.supports-encoded-fmts",  "true");
++	pw_properties_set(props, PW_KEY_NODE_VIRTUAL,                "true");
++	pw_properties_set(props, PW_KEY_PRIORITY_SESSION,            "1");
++	pw_properties_set(props, PW_KEY_PRIORITY_DRIVER,             "1");
++	pw_properties_set(props, "monitor.channel-volumes",          "true");
++	pw_properties_set(props, "monitor.passthrough",              "true");
++	pw_properties_set(props, "compress.offload",                 "true");
++	pw_properties_set(props, PW_KEY_FACTORY_NAME,                "support.null-audio-sink");
++
++	pw_log_info("prepared compress-forwarder alias: name=%s target=%s codec=%s rate=%u channels=%u bitrate=%u media.class=%s audio.format=%s virtual=%s factory=%s",
++			pw_properties_get(props, PW_KEY_NODE_NAME),
++			pw_properties_get(props, "compress.target.object"),
++			pw_properties_get(props, "codec.type"),
++			rate, channels, bitrate,
++			pw_properties_get(props, PW_KEY_MEDIA_CLASS),
++			pw_properties_get(props, PW_KEY_AUDIO_FORMAT),
++			pw_properties_get(props, PW_KEY_NODE_VIRTUAL),
++			pw_properties_get(props, PW_KEY_FACTORY_NAME));
++
++	return 0;
++}
++
++static const struct spa_dict_item module_compress_offload_sink_info[] = {
++	{ PW_KEY_MODULE_AUTHOR,      "Qualcomm Technologies, Inc." },
++	{ PW_KEY_MODULE_DESCRIPTION, "Pulse-visible alias sink for compressed offload playback" },
++	{ PW_KEY_MODULE_USAGE,       pulse_module_options },
++	{ PW_KEY_MODULE_VERSION,     PACKAGE_VERSION },
++};
++
++DEFINE_MODULE_INFO(module_compress_offload_sink) = {
++	.name       = "module-compress-offload-sink",
++	.prepare    = module_compress_offload_sink_prepare,
++	.load       = module_compress_offload_sink_load,
++	.unload     = module_compress_offload_sink_unload,
++	.properties = &SPA_DICT_INIT_ARRAY(module_compress_offload_sink_info),
++	.data_size  = sizeof(struct module_compress_offload_sink_data),
++};
+diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c
+index eb3233b..61f0dfb 100644
+--- a/src/modules/module-protocol-pulse/pulse-server.c
++++ b/src/modules/module-protocol-pulse/pulse-server.c
+@@ -84,6 +84,9 @@ struct temporary_move_data {
+ 	uint8_t used:1;
+ };
+
++/* Buffer size used for compress-offload streams (frame_size == 1). */
++#define COMPRESS_OFFLOAD_BUF_SIZE  16484u
++
+ static struct sample *find_sample(struct impl *impl, uint32_t index, const char *name)
+ {
+ 	union pw_map_item *item;
+@@ -1199,10 +1202,18 @@ static const struct spa_pod *get_buffers_param(struct stream *s,
+ 	blocks = 1;
+ 	stride = s->frame_size;
+
++	/* compressed offload uses byte granularity */
++	if (s->frame_size == 1) {
++		size = COMPRESS_OFFLOAD_BUF_SIZE;
++		pw_log_debug("[%s] get_buffers_param: compress offload path size=%u", s->client->name, size);
++		goto build_buffers_param;
++	}
++
+ 	size = defs->quantum_limit * s->frame_size;
+
+ 	pw_log_info("[%s] stride %d size %u", s->client->name, stride, size);
+
++build_buffers_param:
+ 	param = spa_pod_builder_add_object(b,
+ 			SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
+ 			SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(MIN_BUFFERS,
+@@ -1228,6 +1239,23 @@ static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *
+ 	if (id != SPA_PARAM_Format || param == NULL)
+ 		return;
+
++	/* For compress-offload streams, force byte-granularity regardless
++	 * of negotiated format (we connect with S16LE but data is compressed). */
++	{
++		const char *co = stream->props ?
++			pw_properties_get(stream->props, "compress.offload") : NULL;
++		if (co && pw_properties_parse_bool(co)) {
++			uint32_t media_type = 0, media_subtype = 0;
++			spa_format_parse(param, &media_type, &media_subtype);
++			stream->frame_size = 1;
++			stream->rate = stream->ss.rate ? stream->ss.rate :
++				pw_properties_get_uint32(stream->props, "codec.sample_rate", 44100);
++			pw_log_debug("[%s] compress-offload stream_param_changed: forcing frame_size=1 rate=%u subtype=%u",
++				stream->client->name, stream->rate, media_subtype);
++			goto stream_param_format_done;
++		}
++	}
++
+ 	if ((res = format_parse_param(param, false, &stream->ss, &stream->map, NULL, NULL)) < 0) {
+ 		pw_stream_set_error(stream->stream, res, "format not supported");
+ 		return;
+@@ -1243,6 +1271,9 @@ static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *
+ 		return;
+ 	}
+ 	stream->rate = stream->ss.rate;
++stream_param_format_done:
++	pw_log_debug("[%s] stream param done: frame_size=%u rate=%u ss.format=%u",
++			stream->client->name, stream->frame_size, stream->rate, stream->ss.format);
+
+ 	if (stream->create_tag != SPA_ID_INVALID) {
+ 		struct pw_manager_object *peer;
+@@ -1583,6 +1614,98 @@ static void log_format_info(struct impl *impl, enum spa_log_level level, struct
+ 				impl, it->key, it->value);
+ }
+
++static const struct spa_pod *build_compress_offload_format(struct spa_pod_builder *b,
++		uint32_t id, const struct pw_properties *props, uint32_t *rate)
++{
++	const char *codec;
++	struct spa_audio_info info;
++	uint32_t sample_rate, channels, bitrate;
++
++	spa_zero(info);
++	info.media_type = SPA_MEDIA_TYPE_audio;
++	codec = pw_properties_get(props, "codec.type");
++	sample_rate = pw_properties_get_uint32(props, "codec.sample_rate", 44100);
++	channels = pw_properties_get_uint32(props, "codec.channels", 2);
++	bitrate = pw_properties_get_uint32(props, "codec.bit_rate", 128000);
++
++	if (codec == NULL || spa_streq(codec, "mp3")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_mp3;
++		info.info.mp3.rate = sample_rate;
++		info.info.mp3.channels = channels;
++		info.info.mp3.channel_mode = channels == 1 ?
++			SPA_AUDIO_MP3_CHANNEL_MODE_MONO : SPA_AUDIO_MP3_CHANNEL_MODE_STEREO;
++	} else if (spa_streq(codec, "aac") || spa_streq(codec, "aac_adts")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_aac;
++		info.info.aac.rate = sample_rate;
++		info.info.aac.channels = channels;
++		info.info.aac.bitrate = bitrate;
++		info.info.aac.stream_format = SPA_AUDIO_AAC_STREAM_FORMAT_MP4ADTS;
++	} else if (spa_streq(codec, "aac_adif")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_aac;
++		info.info.aac.rate = sample_rate;
++		info.info.aac.channels = channels;
++		info.info.aac.bitrate = bitrate;
++		info.info.aac.stream_format = SPA_AUDIO_AAC_STREAM_FORMAT_ADIF;
++	} else if (spa_streq(codec, "aac_latm")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_aac;
++		info.info.aac.rate = sample_rate;
++		info.info.aac.channels = channels;
++		info.info.aac.bitrate = bitrate;
++		info.info.aac.stream_format = SPA_AUDIO_AAC_STREAM_FORMAT_MP4LATM;
++	} else if (spa_streq(codec, "flac")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_flac;
++		info.info.flac.rate = sample_rate;
++		info.info.flac.channels = channels;
++	} else if (spa_streq(codec, "vorbis")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_vorbis;
++		info.info.vorbis.rate = sample_rate;
++		info.info.vorbis.channels = channels;
++	} else if (spa_streq(codec, "opus")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_opus;
++		info.info.opus.rate = sample_rate;
++		info.info.opus.channels = channels;
++	} else if (spa_streq(codec, "wma") || spa_streq(codec, "wma_std")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_wma;
++		info.info.wma.rate = sample_rate;
++		info.info.wma.channels = channels;
++		info.info.wma.bitrate = bitrate;
++		info.info.wma.profile = SPA_AUDIO_WMA_PROFILE_WMA9;
++	} else if (spa_streq(codec, "wma_pro")) {
++		info.media_subtype = SPA_MEDIA_SUBTYPE_wma;
++		info.info.wma.rate = sample_rate;
++		info.info.wma.channels = channels;
++		info.info.wma.bitrate = bitrate;
++		info.info.wma.profile = SPA_AUDIO_WMA_PROFILE_WMA9_PRO;
++	} else {
++		errno = ENOTSUP;
++		return NULL;
++	}
++	if (rate != NULL)
++		*rate = sample_rate;
++	return spa_format_audio_build(b, id, &info);
++}
++
++static void synthesize_compress_offload_spec(struct sample_spec *ss,
++		struct channel_map *map, const struct pw_properties *props)
++{
++	uint32_t channels;
++	ss->format = SPA_AUDIO_FORMAT_S16_LE;
++	ss->rate = pw_properties_get_uint32(props, "codec.sample_rate", 44100);
++	channels = pw_properties_get_uint32(props, "codec.channels", 2);
++	ss->channels = (uint8_t)(channels > 0 ? channels : 2);
++	spa_zero(*map);
++	switch (ss->channels) {
++	case 1: channel_map_parse("mono", map); break;
++	case 2: channel_map_parse("stereo", map); break;
++	case 3: channel_map_parse("surround-21", map); break;
++	case 4: channel_map_parse("surround-40", map); break;
++	case 5: channel_map_parse("surround-50", map); break;
++	case 6: channel_map_parse("surround-51", map); break;
++	case 8: channel_map_parse("surround-71", map); break;
++	default: channel_map_parse("stereo", map); ss->channels = 2; break;
++	}
++}
++
+ static int do_create_playback_stream(struct client *client, uint32_t command, uint32_t tag, struct message *m)
+ {
+ 	struct impl *impl = client->impl;
+@@ -1609,7 +1732,8 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 		muted_set = false,
+ 		fail_on_suspend = false,
+ 		relative_volume = false,
+-		passthrough = false;
++		passthrough = false,
++		compress_offload = false;
+ 	struct volume volume;
+ 	struct pw_properties *props = NULL;
+ 	uint8_t n_formats = 0;
+@@ -1668,6 +1792,68 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 	}
+ 	o = find_device(client, sink_index, sink_name, true, &is_monitor);
+
++	if (o != NULL) {
++		const struct pw_node_info *ninfo = o->info;
++		const struct spa_dict *sp = (ninfo && ninfo->props) ? ninfo->props : NULL;
++		char node_name_buf[256] = {0};
++		const char *node_name;
++		const char *co;
++		const char *_nn = pw_properties_get(o->props, PW_KEY_NODE_NAME);
++
++		if (_nn)
++			snprintf(node_name_buf, sizeof(node_name_buf), "%s", _nn);
++		node_name = node_name_buf[0] ? node_name_buf : NULL;
++		co = sp ? spa_dict_lookup(sp, "compress.offload") : NULL;
++		pw_log_debug("[%s] compress-offload check: node=%s ninfo=%p co=%s",
++				client->name, node_name ? node_name : "(null)", ninfo, co ? co : "(null)");
++		if (co && spa_atob(co)) {
++			char target_buf[256] = {0};
++			char codec_buf[64] = {0};
++			char rate_buf[32] = {0};
++			char channels_buf[16] = {0};
++			char bitrate_buf[32] = {0};
++			const char *target;
++			const char *codec;
++			const char *rate_s;
++			const char *channels;
++			const char *bitrate;
++			const char *_s;
++
++			if ((_s = spa_dict_lookup(sp, "compress.target.object")) != NULL)
++				snprintf(target_buf, sizeof(target_buf), "%s", _s);
++			if ((_s = spa_dict_lookup(sp, "codec.type")) != NULL)
++				snprintf(codec_buf, sizeof(codec_buf), "%s", _s);
++			if ((_s = spa_dict_lookup(sp, "codec.sample_rate")) != NULL)
++				snprintf(rate_buf, sizeof(rate_buf), "%s", _s);
++			if ((_s = spa_dict_lookup(sp, "codec.channels")) != NULL)
++				snprintf(channels_buf, sizeof(channels_buf), "%s", _s);
++			if ((_s = spa_dict_lookup(sp, "codec.bit_rate")) != NULL)
++				snprintf(bitrate_buf, sizeof(bitrate_buf), "%s", _s);
++
++			target = target_buf[0] ? target_buf : NULL;
++			codec = codec_buf[0] ? codec_buf : NULL;
++			rate_s = rate_buf[0] ? rate_buf : NULL;
++			channels = channels_buf[0] ? channels_buf : NULL;
++			bitrate = bitrate_buf[0] ? bitrate_buf : NULL;
++
++			pw_properties_set(props, "compress.offload", "true");
++			pw_properties_set(props, "item.node.supports-encoded-fmts", "true");
++			pw_properties_set(props, PW_KEY_MEDIA_TYPE, "Audio");
++			pw_properties_set(props, PW_KEY_MEDIA_CATEGORY, "Playback");
++			pw_properties_set(props, PW_KEY_MEDIA_ROLE, "Music");
++			if (codec) pw_properties_set(props, "codec.type", codec);
++			if (rate_s) pw_properties_set(props, "codec.sample_rate", rate_s);
++			if (channels) pw_properties_set(props, "codec.channels", channels);
++			if (bitrate) pw_properties_set(props, "codec.bit_rate", bitrate);
++
++			pw_log_info("[%s] detected compress-offload sink=%s target=%s codec=%s",
++					client->name, node_name ? node_name : "(null)",
++					target ? target : "(null)", codec ? codec : "(null)");
++			pw_log_debug("[%s] compress target=%s - leaving sink_name=%s for virtual sink routing",
++					client->name, target ? target : "(null)", sink_name ? sink_name : "(null)");
++		}
++	}
++
+ 	spa_zero(fix_ss);
+ 	spa_zero(fix_map);
+ 	if ((fix_format || fix_rate || fix_channels) && o != NULL) {
+@@ -1715,6 +1901,9 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 			goto error_protocol;
+ 	}
+
++	compress_offload = pw_properties_parse_bool(
++			pw_properties_get(props, "compress.offload"));
++
+ 	if (client->version >= 21) {
+ 		if (message_get(m,
+ 				TAG_U8, &n_formats,
+@@ -1732,7 +1921,9 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 						TAG_INVALID) < 0)
+ 					goto error_protocol;
+
+-				if (n_params < MAX_FORMATS &&
++				if (compress_offload) {
++					log_format_info(impl, SPA_LOG_LEVEL_DEBUG, &format);
++				} else if (n_params < MAX_FORMATS &&
+ 				    (params[n_params] = format_info_build_param(&b,
+ 						SPA_PARAM_EnumFormat, &format, &r)) != NULL) {
+ 					n_params++;
+@@ -1746,7 +1937,23 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 			}
+ 		}
+ 	}
+-	if (sample_spec_valid(&ss)) {
++	if (compress_offload) {
++		uint32_t compress_rate = 0;
++		if (n_params < MAX_FORMATS &&
++		    (params[n_params] = build_compress_offload_format(&b,
++					SPA_PARAM_EnumFormat, props, &compress_rate)) != NULL) {
++			n_params++;
++			n_valid_formats++;
++			ss_rate = rate = compress_rate;
++			synthesize_compress_offload_spec(&ss, &map, props);
++			pw_log_debug("[%s] synthesized compress-offload format codec=%s rate=%u channels=%u",
++					client->name, pw_properties_get(props, "codec.type"), compress_rate,
++					pw_properties_get_uint32(props, "codec.channels", 2));
++		} else {
++			pw_log_warn("%p: unsupported compress codec:%s",
++					impl, pw_properties_get(props, "codec.type"));
++		}
++	} else if (sample_spec_valid(&ss)) {
+ 		struct sample_spec sfix = ss;
+ 		struct channel_map mfix = map;
+
+@@ -1770,6 +1977,8 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 	if (m->offset != m->length)
+ 		goto error_protocol;
+
++	pw_log_debug("[%s] format check: n_valid=%u n_params=%u compress=%d passthrough=%d",
++			client->name, n_valid_formats, n_params, compress_offload, passthrough);
+ 	if (n_valid_formats == 0)
+ 		goto error_no_formats;
+
+@@ -1806,6 +2015,8 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 	flags = 0;
+ 	if (no_move)
+ 		flags |= PW_STREAM_FLAG_DONT_RECONNECT;
++	if (compress_offload)
++		flags |= PW_STREAM_FLAG_NO_CONVERT;
+
+ 	if (sink_name != NULL) {
+ 		if (o != NULL)
+@@ -1833,14 +2044,35 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
+ 			&stream->stream_listener,
+ 			&stream_events, stream);
+
+-	pw_stream_connect(stream->stream,
+-			PW_DIRECTION_OUTPUT,
+-			SPA_ID_INVALID,
+-			flags |
+-			PW_STREAM_FLAG_AUTOCONNECT |
+-			PW_STREAM_FLAG_RT_PROCESS |
+-			PW_STREAM_FLAG_MAP_BUFFERS,
+-			params, n_params);
++	if (compress_offload) {
++		uint8_t raw_buf[256];
++		struct spa_pod_builder rb = SPA_POD_BUILDER_INIT(raw_buf, sizeof(raw_buf));
++		struct spa_audio_info_raw raw_info = {
++			.format = SPA_AUDIO_FORMAT_S16_LE,
++			.rate = ss.rate ? ss.rate : 44100,
++			.channels = ss.channels ? ss.channels : 2,
++		};
++		const struct spa_pod *raw_params[1];
++		raw_params[0] = spa_format_audio_raw_build(&rb, SPA_PARAM_EnumFormat, &raw_info);
++		pw_log_debug("[%s] pw_stream_connect: using raw S16LE param for compress sink", client->name);
++		pw_stream_connect(stream->stream,
++				PW_DIRECTION_OUTPUT,
++				SPA_ID_INVALID,
++				flags |
++				PW_STREAM_FLAG_AUTOCONNECT |
++				PW_STREAM_FLAG_RT_PROCESS |
++				PW_STREAM_FLAG_MAP_BUFFERS,
++				raw_params, 1);
++	} else {
++		pw_stream_connect(stream->stream,
++				PW_DIRECTION_OUTPUT,
++				SPA_ID_INVALID,
++				flags |
++				PW_STREAM_FLAG_AUTOCONNECT |
++				PW_STREAM_FLAG_RT_PROCESS |
++				PW_STREAM_FLAG_MAP_BUFFERS,
++				params, n_params);
++	}
+
+ 	stream_update_tag_param(stream);
+
+--
+2.43.0
+
diff --git a/meta-multimedia/recipes-multimedia/pipewire/pipewire_1.6.7.bb b/meta-multimedia/recipes-multimedia/pipewire/pipewire_1.6.7.bb
index 50feeaf843..90815ba012 100644
--- a/meta-multimedia/recipes-multimedia/pipewire/pipewire_1.6.7.bb
+++ b/meta-multimedia/recipes-multimedia/pipewire/pipewire_1.6.7.bb
@@ -15,6 +15,7 @@ DEPENDS = "dbus"
 SRCREV = "3b2cb4fb037bf6033b87d3c87ee917b2f686d309"
 BRANCH = "${@oe.utils.trim_version('${PV}', 2)}"
 SRC_URI = "git://gitlab.freedesktop.org/pipewire/pipewire.git;branch=${BRANCH};protocol=https;tag=${PV}"
+SRC_URI += "file://0001-pipewire-compress-offload.patch"
 SRC_URI += "file://0002-spa-plugins-alsa-acp-compat.h-p-is-already-const-do-.patch"
 
 inherit meson pkgconfig systemd gettext useradd
