Index: uspace/srv/audio/hound/Makefile
===================================================================
--- uspace/srv/audio/hound/Makefile	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/Makefile	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -38,4 +38,5 @@
 
 SOURCES = \
+	audio_client.c \
 	audio_device.c \
 	audio_format.c \
Index: uspace/srv/audio/hound/audio_client.c
===================================================================
--- uspace/srv/audio/hound/audio_client.c	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
+++ uspace/srv/audio/hound/audio_client.c	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup audio
+ * @brief HelenOS sound server
+ * @{
+ */
+/** @file
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <str.h>
+
+#include "audio_client.h"
+#include "log.h"
+
+static void init_common(audio_client_t *client, const char *name,
+    const audio_format_t *f, async_sess_t *sess)
+{
+	link_initialize(&client->link);
+	client->name = str_dup(name);
+	client->format = *f;
+	client->sess = sess;
+	client->exch = NULL;
+	client->is_playback = false;
+	client->is_recording = false;
+}
+
+static int client_sink_connection_change(audio_sink_t *sink);
+static int client_source_connection_change(audio_source_t *source);
+static int client_source_update_data(audio_source_t *source, size_t size);
+
+
+audio_client_t *audio_client_get_playback(
+    const char *name, const audio_format_t *f, async_sess_t *sess)
+{
+	audio_client_t *client = malloc(sizeof(audio_client_t));
+	if (!client)
+		return NULL;
+	init_common(client, name, f, sess);
+	audio_source_init(&client->source, name, client,
+	    client_source_connection_change, client_source_update_data, f);
+	client->is_playback = true;
+	return client;
+}
+
+audio_client_t *audio_client_get_recording(
+    const char *name, const audio_format_t *f, async_sess_t *sess)
+{
+	audio_client_t *client = malloc(sizeof(audio_client_t));
+	if (!client)
+		return NULL;
+	init_common(client, name, f, sess);
+	audio_sink_init(&client->sink, name, client,
+	    client_sink_connection_change, f);
+	client->is_recording = true;
+	return client;
+}
+
+void audio_client_destroy(audio_client_t *client)
+{
+	if (!client)
+		return;
+	if (client->is_recording) {
+		/* There is a fibril running */
+		client->is_recording = false;
+		return;
+	}
+	async_exchange_end(client->exch);
+	async_hangup(client->sess);
+	free(client->name);
+	if (client->is_playback) {
+		audio_source_fini(&client->source);
+	} else { /* was recording */
+		audio_sink_fini(&client->sink);
+	}
+	free(client);
+}
+
+static int client_sink_connection_change(audio_sink_t *sink)
+{
+	//TODO create fibril
+	return ENOTSUP;
+}
+
+static int client_source_connection_change(audio_source_t *source)
+{
+	assert(source);
+	audio_client_t *client = source->private_data;
+	if (source->connected_sink) {
+		client->exch = async_exchange_begin(client->sess);
+		return client->exch ? EOK : ENOMEM;
+	}
+	async_exchange_end(client->exch);
+	client->exch = NULL;
+	return EOK;
+}
+
+static int client_source_update_data(audio_source_t *source, size_t size)
+{
+	assert(source);
+	audio_client_t *client = source->private_data;
+	void *buffer = malloc(size);
+	if (!buffer)
+		return ENOMEM;
+	assert(client->exch);
+	int ret = async_data_read_start(client->exch, buffer, size);
+	if (ret != EOK) {
+		log_debug("Failed to read data from client");
+		free(buffer);
+		return ret;
+	}
+	void *old_buffer = source->available_data.base;
+	source->available_data.base = buffer;
+	source->available_data.size = size;
+	free(old_buffer);
+
+	return EOK;
+}
Index: uspace/srv/audio/hound/audio_client.h
===================================================================
--- uspace/srv/audio/hound/audio_client.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
+++ uspace/srv/audio/hound/audio_client.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup audio
+ * @brief HelenOS sound server
+ * @{
+ */
+/** @file
+ */
+
+#ifndef AUDIO_CLIENT_H_
+#define AUDIO_CLIENT_H_
+
+#include <adt/list.h>
+#include <async.h>
+
+#include "audio_format.h"
+#include "audio_source.h"
+#include "audio_sink.h"
+
+typedef struct {
+	link_t link;
+	const char *name;
+	audio_source_t source;
+	audio_sink_t sink;
+	audio_format_t format;
+	async_sess_t *sess;
+	async_exch_t *exch;
+	bool is_playback;
+	bool is_recording;
+} audio_client_t;
+
+static inline audio_client_t * audio_client_list_instance(link_t *l)
+{
+	return list_get_instance(l, audio_client_t, link);
+}
+
+audio_client_t *audio_client_get_playback(
+    const char *name, const audio_format_t *f, async_sess_t *sess);
+audio_client_t *audio_client_get_recording(
+    const char *name, const audio_format_t *f, async_sess_t *sess);
+void audio_client_destroy(audio_client_t *client);
+
+#endif
Index: uspace/srv/audio/hound/audio_device.c
===================================================================
--- uspace/srv/audio/hound/audio_device.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/audio_device.c	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -49,6 +49,6 @@
 #define BUFFER_BLOCKS 2
 
-static int device_sink_connection_callback(void* arg);
-static int device_source_connection_callback(void* arg, const audio_format_t *f);
+static int device_sink_connection_callback(audio_sink_t *sink);
+static int device_source_connection_callback(audio_source_t *source);
 static void device_event_callback(ipc_callid_t iid, ipc_call_t *icall, void *arg);
 static int get_buffer(audio_device_t *dev);
@@ -72,11 +72,8 @@
 	}
 
-	audio_sink_init(&dev->sink, name);
-	audio_source_init(&dev->source, name);
-
-	audio_sink_set_connected_callback(&dev->sink,
-	    device_sink_connection_callback, dev);
-	audio_source_set_connected_callback(&dev->source,
-	    device_source_connection_callback, dev);
+	audio_sink_init(&dev->sink, name, dev, device_sink_connection_callback,
+	    &AUDIO_FORMAT_ANY);
+	audio_source_init(&dev->source, name, dev,
+	    device_source_connection_callback, NULL, &AUDIO_FORMAT_ANY);
 
 	/* Init buffer members */
@@ -93,9 +90,14 @@
 	return EOK;
 }
-
-static int device_sink_connection_callback(void* arg)
-{
-	audio_device_t *dev = arg;
-	if (list_count(&dev->sink.sources) == 1) {
+void audio_device_fini(audio_device_t *dev)
+{
+	//TODO implement;
+}
+
+static int device_sink_connection_callback(audio_sink_t* sink)
+{
+	assert(sink);
+	audio_device_t *dev = sink->private_data;
+	if (list_count(&sink->sources) == 1) {
 		int ret = get_buffer(dev);
 		if (ret != EOK) {
@@ -112,5 +114,5 @@
 		}
 	}
-	if (list_count(&dev->sink.sources) == 0) {
+	if (list_count(&sink->sources) == 0) {
 		int ret = stop_playback(dev);
 		if (ret != EOK) {
@@ -130,8 +132,9 @@
 }
 
-static int device_source_connection_callback(void* arg, const audio_format_t *f)
-{
-	audio_device_t *dev = arg;
-	if (f) { /* Connected, f points to sink format */
+static int device_source_connection_callback(audio_source_t *source)
+{
+	assert(source);
+	audio_device_t *dev = source->private_data;
+	if (source->connected_sink) {
 		int ret = get_buffer(dev);
 		if (ret != EOK) {
@@ -147,6 +150,5 @@
 			return ret;
 		}
-		dev->source.format = *f;
-	} else { /* Disconnected, f is NULL */
+	} else { /* Disconnected */
 		int ret = stop_recording(dev);
 		if (ret != EOK) {
@@ -155,5 +157,5 @@
 			return ret;
 		}
-		dev->sink.format = AUDIO_FORMAT_ANY;
+		source->format = AUDIO_FORMAT_ANY;
 		ret = release_buffer(dev);
 		if (ret != EOK) {
Index: uspace/srv/audio/hound/audio_device.h
===================================================================
--- uspace/srv/audio/hound/audio_device.h	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/audio_device.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -44,5 +44,4 @@
 #include <ipc/loc.h>
 
-#include "audio_format.h"
 #include "audio_source.h"
 #include "audio_sink.h"
@@ -65,5 +64,5 @@
 } audio_device_t;
 
-static inline audio_device_t * list_audio_device_instance(link_t *l)
+static inline audio_device_t * audio_device_list_instance(link_t *l)
 {
 	return list_get_instance(l, audio_device_t, link);
@@ -71,5 +70,5 @@
 
 int audio_device_init(audio_device_t *dev, service_id_t id, const char *name);
-
+void audio_device_fini(audio_device_t *dev);
 static inline audio_source_t * audio_device_get_source(audio_device_t *dev)
 {
@@ -87,9 +86,4 @@
 int audio_device_available_buffer(audio_device_t *dev, void **base, size_t *size);
 
-int audio_device_playback_start(audio_device_t *dev, const audio_format_t *format, unsigned latency);
-int audio_device_record_start(audio_device_t *dev, const audio_format_t *format, unsigned latency);
-int audio_device_playback_stop(audio_device_t *dev);
-int audio_device_record_stop(audio_device_t *dev);
-
 #endif
 
Index: uspace/srv/audio/hound/audio_sink.c
===================================================================
--- uspace/srv/audio/hound/audio_sink.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/audio_sink.c	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -43,25 +43,8 @@
 #include "log.h"
 
-#if 0
-static int loop(void* arg)
-{
-	audio_sink_t *sink = arg;
-	assert(sink);
-	while (sink->device) {
-		while (sink->running) {
-			//wait for usable buffer
-			audio_sink_mix_inputs(sink,
-			    sink->device->buffer.available_base,
-			    sink->device->buffer.available_size);
-		}
-		//remove ready
-		sleep(1);
-	}
-	return 0;
-}
-#endif
 
-
-int audio_sink_init(audio_sink_t *sink, const char* name)
+int audio_sink_init(audio_sink_t *sink, const char *name,
+    void *private_data,int (*connection_change)(audio_sink_t *sink),
+    const audio_format_t *f)
 {
 	assert(sink);
@@ -73,9 +56,18 @@
 	list_initialize(&sink->sources);
 	sink->name = str_dup(name);
-	sink->format = AUDIO_FORMAT_ANY;
-	log_verbose("Initialized sink (%p) '%s' with ANY audio format",
-	    sink, sink->name);
+	sink->private_data = private_data;
+	sink->format = *f;
+	log_verbose("Initialized sink (%p) '%s'", sink, sink->name);
 	return EOK;
 }
+
+void audio_sink_fini(audio_sink_t *sink)
+{
+	assert(sink);
+	assert(!sink->private_data);
+	free(sink->name);
+	sink->name = NULL;
+}
+
 
 int audio_sink_add_source(audio_sink_t *sink, audio_source_t *source)
@@ -111,9 +103,8 @@
 	}
 
-	if (sink->connected_change.hook) {
-		const int ret =
-		    sink->connected_change.hook(sink->connected_change.arg);
+	if (sink->connection_change) {
+		const int ret = sink->connection_change(sink);
 		if (ret != EOK) {
-			log_debug("Connected hook failed.");
+			log_debug("Connection hook failed.");
 			list_remove(&source->link);
 			sink->format = old_format;
@@ -131,9 +122,10 @@
 	assert(list_member(&source->link, &sink->sources));
 	list_remove(&source->link);
-	if (sink->connected_change.hook) {
-		const int ret =
-		    sink->connected_change.hook(sink->connected_change.arg);
+	if (sink->connection_change) {
+		const int ret = sink->connection_change(sink);
 		if (ret != EOK) {
 			log_debug("Connected hook failed.");
+			list_append(&source->link, &sink->sources);
+			return ret;
 		}
 	}
Index: uspace/srv/audio/hound/audio_sink.h
===================================================================
--- uspace/srv/audio/hound/audio_sink.h	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/audio_sink.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -37,31 +37,34 @@
 #define AUDIO_SINK_H_
 
+#include <adt/list.h>
+#include <async.h>
 #include <bool.h>
-#include <adt/list.h>
 #include <pcm_sample_format.h>
 #include <fibril.h>
 
+#include "audio_source.h"
 #include "audio_format.h"
-#include "audio_source.h"
 
-typedef struct audio_sink {
+typedef struct audio_sink audio_sink_t;
+
+struct audio_sink {
 	link_t link;
 	list_t sources;
-	char *name;
+	const char *name;
 	audio_format_t format;
-	struct {
-		int (*hook)(void* arg);
-		void *arg;
-	} connected_change;
-} audio_sink_t;
+	void *private_data;
+	int (*connection_change)(audio_sink_t *sink);
+};
 
-static inline void audio_sink_set_connected_callback(audio_sink_t *sink,
-    int (*hook)(void* arg), void* arg)
+static inline audio_sink_t * audio_sink_list_instance(link_t *l)
 {
-	assert(sink);
-	sink->connected_change.arg = arg;
-	sink->connected_change.hook = hook;
-};
-int audio_sink_init(audio_sink_t *sink, const char* name);
+	return list_get_instance(l, audio_sink_t, link);
+}
+
+int audio_sink_init(audio_sink_t *sink, const char *name,
+    void *private_data, int (*connection_change)(audio_sink_t *sink),
+    const audio_format_t *f);
+void audio_sink_fini(audio_sink_t *sink);
+
 int audio_sink_add_source(audio_sink_t *sink, audio_source_t *source);
 int audio_sink_remove_source(audio_sink_t *sink, audio_source_t *source);
Index: uspace/srv/audio/hound/audio_source.c
===================================================================
--- uspace/srv/audio/hound/audio_source.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/audio_source.c	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -42,11 +42,15 @@
 
 #include "audio_source.h"
+#include "audio_sink.h"
 #include "log.h"
 
 
-int audio_source_init(audio_source_t *source, const char* name)
+int audio_source_init(audio_source_t *source, const char *name, void *data,
+    int (*connection_change)(audio_source_t *),
+    int (*update_available_data)(audio_source_t *, size_t),
+    const audio_format_t *f)
 {
 	assert(source);
-	if (!name) {
+	if (!name || !f) {
 		log_debug("Incorrect parameters.");
 		return EINVAL;
@@ -54,24 +58,44 @@
 	link_initialize(&source->link);
 	source->name = str_dup(name);
-	source->connected_change.hook = NULL;
-	source->connected_change.arg = NULL;
-	source->get_data.hook = NULL;
-	source->get_data.arg = NULL;
-	source->available.base = NULL;
-	source->available.size = 0;
-	log_verbose("Initialized source (%p) '%s' with ANY audio format",
-	    source, source->name);
+	source->private_data = data;
+	source->connection_change = connection_change;
+	source->update_available_data = update_available_data;
+	source->connected_sink = NULL;
+	source->format = *f;
+	source->available_data.base = NULL;
+	source->available_data.size = 0;
+	log_verbose("Initialized source (%p) '%s'", source, source->name);
 	return EOK;
 }
 
-int audio_source_connected(audio_source_t *source, const audio_format_t *f)
+void audio_source_fini(audio_source_t *source)
+{
+	if (!source)
+		return;
+	assert(source->connected_sink == NULL);
+	free(source->name);
+	free(source);
+}
+
+int audio_source_connected(audio_source_t *source, struct audio_sink *sink)
 {
 	assert(source);
-	if (!f) {
-		log_debug("Incorrect parameters.");
-		return EINVAL;
+	audio_sink_t *old_sink = source->connected_sink;
+	const audio_format_t old_format = source->format;
+
+	source->connected_sink = sink;
+	if (audio_format_is_any(&source->format)) {
+		assert(sink);
+		assert(!audio_format_is_any(&sink->format));
+		source->format = sink->format;
 	}
-	if (source->connected_change.hook)
-		source->connected_change.hook(source->connected_change.arg, f);
+	if (source->connection_change) {
+		const int ret = source->connection_change(source);
+		if (ret != EOK) {
+			source->format = old_format;
+			source->connected_sink = old_sink;
+			return ret;
+		}
+	}
 	return EOK;
 }
@@ -96,19 +120,31 @@
 		return ENOTSUP;
 	}
-
-	if (source->available.size == 0) {
-		log_debug("No data to add");
-		return EOVERFLOW; /* In fact this is underflow... */
+	if (source->available_data.base == NULL ||
+	    source->available_data.size == 0) {
+		int ret = EOVERFLOW; /* In fact this is underflow... */
+		if (source->update_available_data)
+			ret = source->update_available_data(source, size);
+		if (ret != EOK) {
+			log_debug("No data to add");
+			return ret;
+		}
 	}
 
-	const size_t real_size = min(size, source->available.size);
+	const size_t real_size = min(size, source->available_data.size);
 	const int ret =
-	    audio_format_mix(buffer, source->available.base, real_size, f);
+	    audio_format_mix(buffer, source->available_data.base, real_size, f);
 	if (ret != EOK) {
 		log_debug("Mixing failed");
 		return ret;
 	}
-	source->available.base += real_size;
-	source->available.size -= real_size;
+	source->available_data.base += real_size;
+	source->available_data.size -= real_size;
+	buffer += real_size;
+	size -= real_size;
+
+	//TODO update data again
+	if (size)
+		log_warning("not enough data");
+
 	return EOK;
 }
Index: uspace/srv/audio/hound/audio_source.h
===================================================================
--- uspace/srv/audio/hound/audio_source.h	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/audio_source.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -41,24 +41,23 @@
 #include <pcm_sample_format.h>
 
+
 #include "audio_format.h"
 
+struct audio_sink;
+typedef struct audio_source audio_source_t;
 
-typedef struct {
+struct audio_source {
 	link_t link;
-	char *name;
-	struct {
-		int (*hook)(void* arg, const audio_format_t *f);
-		void *arg;
-	} connected_change;
-	struct {
-		int (*hook)(void* arg);
-		void *arg;
-	} get_data;
+	const char *name;
+	audio_format_t format;
+	void *private_data;
+	int (*connection_change)(audio_source_t *source);
+	int (*update_available_data)(audio_source_t *source, size_t size);
+	struct audio_sink *connected_sink;
 	struct {
 		void *base;
 		size_t size;
-	} available;
-	audio_format_t format;
-} audio_source_t;
+	} available_data;
+};
 
 static inline audio_source_t * audio_source_list_instance(link_t *l)
@@ -67,13 +66,10 @@
 }
 
-int audio_source_init(audio_source_t *source, const char *name);
-static inline void audio_source_set_connected_callback(audio_source_t *source,
-    int (*hook)(void* arg, const audio_format_t *f), void* arg)
-{
-	assert(source);
-	source->connected_change.arg = arg;
-	source->connected_change.hook = hook;
-}
-int audio_source_connected(audio_source_t *source, const audio_format_t *f);
+int audio_source_init(audio_source_t *source, const char *name, void *data,
+    int (*connection_change)(audio_source_t *),
+    int (*update_available_data)(audio_source_t *, size_t),
+    const audio_format_t *f);
+void audio_source_fini(audio_source_t *source);
+int audio_source_connected(audio_source_t *source, struct audio_sink *sink);
 int audio_source_add_self(audio_source_t *source, void *buffer, size_t size,
     const audio_format_t *f);
Index: uspace/srv/audio/hound/hound.c
===================================================================
--- uspace/srv/audio/hound/hound.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/hound.c	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -39,4 +39,5 @@
 
 #include "hound.h"
+#include "audio_client.h"
 #include "audio_device.h"
 #include "audio_sink.h"
@@ -46,15 +47,45 @@
 #include "str_error.h"
 
+#define FIND_BY_NAME(type) \
+do { \
+	assert(list); \
+	assert(name); \
+	list_foreach(*list, it) { \
+		audio_ ## type ## _t *dev = \
+		    audio_ ## type ## _list_instance(it); \
+		if (str_cmp(name, dev->name) == 0) { \
+			log_debug("%s with name %s is already present", \
+			    #type, name); \
+			return NULL; \
+		} \
+	} \
+	return NULL; \
+} while (0)
+
+static audio_device_t * find_device_by_name(list_t *list, const char *name)
+{
+	FIND_BY_NAME(device);
+}
+static audio_source_t * find_source_by_name(list_t *list, const char *name)
+{
+	FIND_BY_NAME(source);
+}
+static audio_sink_t * find_sink_by_name(list_t *list, const char *name)
+{
+	FIND_BY_NAME(sink);
+}
+
 int hound_init(hound_t *hound)
 {
 	assert(hound);
+	fibril_mutex_initialize(&hound->list_guard);
 	list_initialize(&hound->devices);
+	list_initialize(&hound->sources);
 	list_initialize(&hound->available_sources);
 	list_initialize(&hound->sinks);
-	list_initialize(&hound->clients);
 	return EOK;
 }
 
-int hound_add_device(hound_t *hound, service_id_t id, const char* name)
+int hound_add_device(hound_t *hound, service_id_t id, const char *name)
 {
 	log_verbose("Adding device \"%s\", service: %zu", name, id);
@@ -67,5 +98,5 @@
 
 	list_foreach(hound->devices, it) {
-		audio_device_t *dev = list_audio_device_instance(it);
+		audio_device_t *dev = audio_device_list_instance(it);
 		if (dev->id == id) {
 			log_debug("Device with id %zu is already present", id);
@@ -74,5 +105,11 @@
 	}
 
-	audio_device_t *dev = malloc(sizeof(audio_device_t));
+	audio_device_t *dev = find_device_by_name(&hound->devices, name);
+	if (dev) {
+		log_debug("Device with name %s is already present", name);
+		return EEXISTS;
+	}
+
+	dev = malloc(sizeof(audio_device_t));
 	if (!dev) {
 		log_debug("Failed to malloc device structure.");
@@ -80,4 +117,5 @@
 	}
 	const int ret = audio_device_init(dev, id, name);
+	free(name);
 	if (ret != EOK) {
 		log_debug("Failed to initialize new audio device: %s",
@@ -88,16 +126,28 @@
 
 	list_append(&dev->link, &hound->devices);
-	log_info("Added new device: '%s'", name);
+	log_info("Added new device: '%s'", dev->name);
 
 	audio_source_t *source = audio_device_get_source(dev);
 	if (source) {
+		const int ret = hound_add_source(hound, source);
+		if (ret != EOK) {
+			log_debug("Failed to add device source: %s",
+			    str_error(ret));
+			audio_device_fini(dev);
+			return ret;
+		}
 		log_verbose("Added source: '%s'.", source->name);
-		list_append(&source->link, &hound->available_sources);
 	}
 
 	audio_sink_t *sink = audio_device_get_sink(dev);
 	if (sink) {
+		const int ret = hound_add_sink(hound, sink);
+		if (ret != EOK) {
+			log_debug("Failed to add device sink: %s",
+			    str_error(ret));
+			audio_device_fini(dev);
+			return ret;
+		}
 		log_verbose("Added sink: '%s'.", sink->name);
-		list_append(&sink->link, &hound->sinks);
 	}
 
@@ -108,4 +158,48 @@
 }
 
+int hound_add_source(hound_t *hound, audio_source_t *source)
+{
+	assert(hound);
+	if (!source || !source->name) {
+		log_debug("Invalid source specified.");
+		return EINVAL;
+	}
+	fibril_mutex_lock(&hound->list_guard);
+	if (find_source_by_name(&hound->sources, source->name)) {
+		log_debug("Source by that name already exists");
+		fibril_mutex_unlock(&hound->list_guard);
+		return EEXISTS;
+	}
+	list_foreach(hound->sinks, it) {
+		audio_sink_t *sink = audio_sink_list_instance(it);
+		if (find_source_by_name(&sink->sources, source->name)) {
+			log_debug("Source by that name already exists");
+			fibril_mutex_unlock(&hound->list_guard);
+			return EEXISTS;
+		}
+	}
+	list_append(&source->link, &hound->sources);
+	fibril_mutex_unlock(&hound->list_guard);
+	return EOK;
+}
+
+int hound_add_sink(hound_t *hound, audio_sink_t *sink)
+{
+	assert(hound);
+	if (!sink || !sink->name) {
+		log_debug("Invalid source specified.");
+		return EINVAL;
+	}
+	fibril_mutex_lock(&hound->list_guard);
+	if (find_sink_by_name(&hound->sinks, sink->name)) {
+		log_debug("Sink by that name already exists");
+		fibril_mutex_unlock(&hound->list_guard);
+		return EEXISTS;
+	}
+	list_append(&sink->link, &hound->sinks);
+	fibril_mutex_unlock(&hound->list_guard);
+	return EOK;
+}
+
 /**
  * @}
Index: uspace/srv/audio/hound/hound.h
===================================================================
--- uspace/srv/audio/hound/hound.h	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/hound.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -41,8 +41,15 @@
 #include <ipc/loc.h>
 #include <errno.h>
+#include <fibril_synch.h>
+
+#include "audio_source.h"
+#include "audio_sink.h"
+#include "audio_format.h"
+
 
 typedef struct {
+	fibril_mutex_t list_guard;
 	list_t devices;
-	list_t clients;
+	list_t sources;
 	list_t available_sources;
 	list_t sinks;
@@ -51,6 +58,8 @@
 int hound_init(hound_t *hound);
 int hound_add_device(hound_t *hound, service_id_t id, const char* name);
-int hound_add_playback_client(hound_t *hound, const char* name);
-int hound_add_record_client(hound_t *hound, const char* name);
+int hound_add_source(hound_t *hound, audio_source_t *source);
+int hound_add_sink(hound_t *hound, audio_sink_t *sink);
+int hound_connect(const char* source_name, const char* sink_name);
+int hound_disconnect(const char* source_name, const char* sink_name);
 
 #endif
Index: uspace/srv/audio/hound/main.c
===================================================================
--- uspace/srv/audio/hound/main.c	(revision 992ef56e47be6fbb1ac36e825a7bf120deb45825)
+++ uspace/srv/audio/hound/main.c	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -47,10 +47,44 @@
 #define NAMESPACE "audio"
 #define NAME "hound"
-
 #define CATEGORY "audio-pcm"
 
+#include "audio_client.h"
 #include "log.h"
-
-hound_t hound;
+#include "protocol.h"
+
+static hound_t hound;
+
+static inline audio_format_t read_format(const ipc_call_t *call)
+{
+	audio_format_t format = {
+		.channels = IPC_GET_ARG1(*call),
+		.sampling_rate = IPC_GET_ARG2(*call),
+		.sample_format = IPC_GET_ARG3(*call),
+	};
+	return format;
+}
+static inline const char *get_name()
+{
+	size_t size = 0;
+	ipc_callid_t callid;
+	async_data_read_receive(&callid, &size);
+	char *buffer = malloc(size);
+	if (buffer) {
+		async_data_read_finalize(callid, buffer, size);
+		buffer[size - 1] = 0;
+		log_verbose("Got name from client: %s", buffer);
+	}
+	return buffer;
+}
+static inline async_sess_t *get_session()
+{
+	ipc_call_t call;
+	ipc_callid_t callid = async_get_call(&call);
+	async_sess_t *s = async_callback_receive_start(EXCHANGE_ATOMIC, &call);
+	async_answer_0(callid, s ? EOK : ENOMEM);
+	log_verbose("Received callback session");
+	return s;
+}
+
 
 static void scan_for_devices(void)
@@ -96,7 +130,95 @@
 
 	free(svcs);
-
-}
-
+}
+
+static void client_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	async_answer_0(iid, EOK);
+
+	LIST_INITIALIZE(local_playback);
+	LIST_INITIALIZE(local_recording);
+
+	while (1) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+		log_debug("Got method %u", IPC_GET_IMETHOD(call));
+		switch (IPC_GET_IMETHOD(call)) {
+		case HOUND_REGISTER_PLAYBACK: {
+			const audio_format_t format = read_format(&call);
+			const char *name = get_name();
+			async_sess_t *sess = get_session();
+			audio_client_t * client =
+			    audio_client_get_playback(name, &format, sess);
+			if (!client) {
+				log_error("Failed to create playback client");
+				async_answer_0(callid, ENOMEM);
+			}
+			int ret = hound_add_source(&hound, &client->source);
+			if (ret != EOK){
+				audio_client_destroy(client);
+				log_error("Failed to add audio source: %s",
+				    str_error(ret));
+				async_answer_0(callid, ret);
+				break;
+			}
+			async_answer_0(callid, EOK);
+			list_append(&client->link, &local_playback);
+			break;
+		}
+		case HOUND_REGISTER_RECORDING: {
+			const audio_format_t format = read_format(&call);
+			const char *name = get_name();
+			async_sess_t *sess = get_session();
+			audio_client_t * client =
+			    audio_client_get_recording(name, &format, sess);
+			if (!client) {
+				log_error("Failed to create recording client");
+				async_answer_0(callid, ENOMEM);
+				break;
+			}
+			int ret = hound_add_sink(&hound, &client->sink);
+			if (ret != EOK){
+				audio_client_destroy(client);
+				log_error("Failed to add audio sink: %s",
+				    str_error(ret));
+				async_answer_0(callid, ret);
+				break;
+			}
+			async_answer_0(callid, EOK);
+			list_append(&client->link, &local_recording);
+			break;
+		}
+		case HOUND_UNREGISTER_PLAYBACK: {
+			//const char *name = get_name();
+			//TODO unregister in hound
+			//TODO remove from local
+			break;
+		}
+		case HOUND_UNREGISTER_RECORDING: {
+			//TODO Get Name
+			//TODO unregister in hound
+			//TODO remove from local
+			break;
+		}
+		case HOUND_CONNECT: {
+			//TODO Get Name
+			//TODO Get Name
+			//TODO connect in hound
+			break;
+		}
+		case HOUND_DISCONNECT: {
+			//TODO Get Name
+			//TODO Get Name
+			//TODO disconnect in hound
+			break;
+		}
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		case 0:
+			return;
+		}
+	}
+}
 
 int main(int argc, char **argv)
@@ -106,13 +228,37 @@
 	int ret = hound_init(&hound);
 	if (ret != EOK) {
-		log_error("Failed to initialize hound structure: %s\n",
-		    str_error(ret));
-		return 1;
+		log_fatal("Failed to initialize hound structure: %s",
+		    str_error(ret));
+		return -ret;
+	}
+
+	async_set_client_connection(client_connection);
+	ret = loc_server_register(NAME);
+	if (ret != EOK) {
+		log_fatal("Failed to register sound server: %s",
+		    str_error(ret));
+		return -ret;
+	}
+
+	char fqdn[LOC_NAME_MAXLEN + 1];
+	snprintf(fqdn, LOC_NAME_MAXLEN, "%s/%s", NAMESPACE, NAME);
+	service_id_t id = 0;
+	ret = loc_service_register(fqdn, &id);
+	if (ret != EOK) {
+		log_fatal("Failed to register sound service: %s",
+		    str_error(ret));
+		return -ret;
 	}
 
 	ret = loc_register_cat_change_cb(scan_for_devices);
+	if (ret != EOK) {
+		log_fatal("Failed to register for category changes: %s",
+		    str_error(ret));
+		loc_service_unregister(id);
+		return -ret;
+	}
+	log_info("Running with service id %u", id);
 
 	scan_for_devices();
-
 
 	async_manager();
Index: uspace/srv/audio/hound/protocol.h
===================================================================
--- uspace/srv/audio/hound/protocol.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
+++ uspace/srv/audio/hound/protocol.h	(revision 1df3018aba16e9a26b7b9df22c85eb411795797c)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 Jan Vesely
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup audio
+ * @brief HelenOS sound server
+ * @{
+ */
+/** @file
+ */
+
+#ifndef PROTOCOL_H_
+#define PROTOCOL_H_
+
+#include <async.h>
+
+enum {
+	HOUND_REGISTER_PLAYBACK = IPC_FIRST_USER_METHOD,
+	HOUND_REGISTER_RECORDING,
+	HOUND_UNREGISTER_PLAYBACK,
+	HOUND_UNREGISTER_RECORDING,
+	HOUND_CONNECT,
+	HOUND_DISCONNECT,
+};
+
+#endif
+
