Index: uspace/srv/audio/hound/audio_data.c
===================================================================
--- uspace/srv/audio/hound/audio_data.c	(revision 4b33db8e00bfd70f1180d025176497c8264bab2b)
+++ uspace/srv/audio/hound/audio_data.c	(revision d988ef2a47fc17216b02595ca71934247ff2ce63)
@@ -34,8 +34,22 @@
  */
 
+#include <macros.h>
 #include <malloc.h>
 #include "audio_data.h"
 
-static void ref_inc(audio_data_t *adata)
+audio_data_t *audio_data_create(const void *data, size_t size,
+    pcm_format_t format)
+{
+	audio_data_t *adata = malloc(sizeof(audio_data_t));
+	if (adata) {
+		adata->data = data;
+		adata->size = size;
+		adata->format = format;
+		atomic_set(&adata->refcount, 1);
+	}
+	return adata;
+}
+
+void audio_data_addref(audio_data_t *adata)
 {
 	assert(adata);
@@ -44,5 +58,5 @@
 }
 
-static void ref_dec(audio_data_t *adata)
+void audio_data_unref(audio_data_t *adata)
 {
 	assert(adata);
@@ -55,22 +69,4 @@
 }
 
-audio_data_t *audio_data_create(const void *data, size_t size,
-    pcm_format_t format)
-{
-	audio_data_t *adata = malloc(sizeof(audio_data_t));
-	if (adata) {
-		adata->data = data;
-		adata->size = size;
-		adata->format = format;
-		atomic_set(&adata->refcount, 1);
-	}
-	return adata;
-}
-
-void audio_data_unref(audio_data_t *adata)
-{
-	ref_dec(adata);
-}
-
 audio_data_link_t *audio_data_link_create(audio_data_t *adata)
 {
@@ -78,5 +74,5 @@
 	audio_data_link_t *link = malloc(sizeof(audio_data_link_t));
 	if (link) {
-		ref_inc(adata);
+		audio_data_addref(adata);
 		link->adata = adata;
 		link->position = 0;
@@ -103,5 +99,5 @@
 	assert(link);
 	assert(!link_in_use(&link->link));
-	ref_dec(link->adata);
+	audio_data_unref(link->adata);
 	free(link);
 }
@@ -111,6 +107,105 @@
 	assert(alink);
 	assert(alink->adata);
-	return pcm_format_size_to_frames(alink->adata->size - alink->position,
+	return pcm_format_size_to_frames(audio_data_link_remain_size(alink),
 	    &alink->adata->format);
+}
+
+/* Audio Pipe */
+
+
+void audio_pipe_init(audio_pipe_t *pipe)
+{
+	assert(pipe);
+	list_initialize(&pipe->list);
+	fibril_mutex_initialize(&pipe->guard);
+	pipe->frames = 0;
+	pipe->bytes = 0;
+}
+
+
+
+void audio_pipe_fini(audio_pipe_t *pipe)
+{
+	assert(pipe);
+	while (!list_empty(&pipe->list)) {
+		audio_data_t *adata = audio_pipe_pop(pipe);
+		audio_data_unref(adata);
+	}
+}
+
+int audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data)
+{
+	assert(pipe);
+	assert(data);
+	audio_data_link_t *alink = audio_data_link_create(data);
+	if (!alink)
+		return ENOMEM;
+
+	fibril_mutex_lock(&pipe->guard);
+	list_append(&alink->link, &pipe->list);
+	pipe->bytes += audio_data_link_remain_size(alink);
+	pipe->frames += audio_data_link_available_frames(alink);
+	fibril_mutex_unlock(&pipe->guard);
+	return EOK;
+}
+
+audio_data_t *audio_pipe_pop(audio_pipe_t *pipe)
+{
+	assert(pipe);
+	fibril_mutex_lock(&pipe->guard);
+	audio_data_t *adata = NULL;
+	link_t *l = list_first(&pipe->list);
+	if (l) {
+		audio_data_link_t *alink = audio_data_link_list_instance(l);
+		list_remove(&alink->link);
+		adata = alink->adata;
+		audio_data_addref(adata);
+		audio_data_link_destroy(alink);
+	}
+	fibril_mutex_unlock(&pipe->guard);
+	return adata;
+}
+
+ssize_t audio_pipe_mix_data(audio_pipe_t *pipe, void *data,
+    size_t size, const pcm_format_t *f)
+{
+	assert(pipe);
+	const size_t dst_frame_size = pcm_format_frame_size(f);
+	size_t needed_frames = size / dst_frame_size;
+	size_t copied_size = 0;
+	fibril_mutex_lock(&pipe->guard);
+	while (needed_frames > 0 && !list_empty(&pipe->list)) {
+		/* Get first audio chunk */
+		link_t *l = list_first(&pipe->list);
+		audio_data_link_t *alink = audio_data_link_list_instance(l);
+
+		/* Get audio chunk metadata */
+		const size_t src_frame_size =
+		    pcm_format_frame_size(&alink->adata->format);
+		const size_t available_frames =
+		    audio_data_link_available_frames(alink);
+		const size_t copy_frames = min(available_frames, needed_frames);
+		const size_t copy_size = copy_frames * dst_frame_size;
+
+		/* Copy audio data */
+		pcm_format_convert_and_mix(data, copy_size,
+		    audio_data_link_start(alink),
+		    audio_data_link_remain_size(alink),
+		    &alink->adata->format, f);
+
+		/* Update values */
+		copied_size += copy_size;
+		needed_frames -= copy_frames;
+		data += copy_size;
+		alink->position += (copy_frames * src_frame_size);
+		if (audio_data_link_remain_size(alink) == 0) {
+			list_remove(&alink->link);
+			audio_data_link_destroy(alink);
+		} else {
+			assert(needed_frames == 0);
+		}
+	}
+	fibril_mutex_unlock(&pipe->guard);
+	return copied_size;
 }
 
Index: uspace/srv/audio/hound/audio_data.h
===================================================================
--- uspace/srv/audio/hound/audio_data.h	(revision 4b33db8e00bfd70f1180d025176497c8264bab2b)
+++ uspace/srv/audio/hound/audio_data.h	(revision d988ef2a47fc17216b02595ca71934247ff2ce63)
@@ -37,7 +37,9 @@
 #define AUDIO_DATA_H_
 
-#include <pcm/format.h>
 #include <adt/list.h>
 #include <atomic.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <pcm/format.h>
 
 typedef struct {
@@ -54,4 +56,11 @@
 } audio_data_link_t;
 
+typedef struct {
+	list_t list;
+	size_t bytes;
+	size_t frames;
+	fibril_mutex_t guard;
+} audio_pipe_t;
+
 static inline audio_data_link_t * audio_data_link_list_instance(link_t *l)
 {
@@ -61,4 +70,5 @@
 audio_data_t * audio_data_create(const void *data, size_t size,
     pcm_format_t format);
+void audio_data_addref(audio_data_t *adata);
 void audio_data_unref(audio_data_t *adata);
 
@@ -83,4 +93,39 @@
 	return alink->adata->size - alink->position;
 }
+
+void audio_pipe_init(audio_pipe_t *pipe);
+void audio_pipe_fini(audio_pipe_t *pipe);
+
+int audio_pipe_push(audio_pipe_t *pipe, audio_data_t *data);
+audio_data_t *audio_pipe_pop(audio_pipe_t *pipe);
+
+ssize_t audio_pipe_mix_data(audio_pipe_t *pipe, void *buffer, size_t size,
+    const pcm_format_t *f);
+
+static inline size_t audio_pipe_bytes(audio_pipe_t *pipe)
+{
+	assert(pipe);
+	return pipe->bytes;
+}
+
+static inline size_t audio_pipe_frames(audio_pipe_t *pipe)
+{
+	assert(pipe);
+	return pipe->frames;
+}
+
+static inline int audio_pipe_push_data(audio_pipe_t *pipe,
+    const void *data, size_t size, pcm_format_t f)
+{
+	audio_data_t *adata = audio_data_create(data, size, f);
+	if (adata) {
+		const int ret = audio_pipe_push(pipe, adata);
+		audio_data_unref(adata);
+		return ret;
+	}
+	return ENOMEM;
+}
+
+
 #endif
 
