diff --git a/repos/os/run/audio_out_click.run b/repos/os/run/audio_out_click.run
new file mode 100644
index 0000000000..90f87f9cac
--- /dev/null
+++ b/repos/os/run/audio_out_click.run
@@ -0,0 +1,119 @@
+assert_spec x86
+
+#
+# Build
+#
+
+set build_components {
+ core init
+ drivers/timer
+ drivers/audio
+ drivers/input
+ server/mixer
+ test/audio_out
+ test/audio_out_click
+}
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+#
+# Config
+#
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_platform_drv_config
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sample.raw
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+
+if {[expr ![file exists bin/sample.raw] || ![file exists bin/click.raw]]} {
+ puts ""
+ puts "The sample and/or click file is missing. Please take a look at"
+ puts "repos/dde_bsd/README, create 'sample.raw' and/or 'click.raw'"
+ puts "and put the file(s) into './bin'. afterwards"
+ puts ""
+ exit 1
+}
+
+#
+# Boot modules
+#
+
+set boot_modules {
+ core init timer mixer ps2_drv audio_drv
+ test-audio_out test-audio_out_click
+ sample.raw click.raw }
+
+# platform-specific modules
+append_platform_drv_boot_modules
+
+build_boot_image $boot_modules
+
+append qemu_args " -m 128 -nographic -soundhw es1370 "
+
+run_genode_until forever
diff --git a/repos/os/src/test/audio_out_click/README b/repos/os/src/test/audio_out_click/README
new file mode 100644
index 0000000000..770d87cc9f
--- /dev/null
+++ b/repos/os/src/test/audio_out_click/README
@@ -0,0 +1,14 @@
+test-audio_out sends one or more raw audio streams to the "Audio_out"
+service. The raw data must comply the Audio_out standard format.
+
+!
+! test-audio_out
+! 1M
+!
+! audio1.raw
+! audio2.raw
+! ...
+!
+!
+
+ Example configuration entry
diff --git a/repos/os/src/test/audio_out_click/main.cc b/repos/os/src/test/audio_out_click/main.cc
new file mode 100644
index 0000000000..b2a1948a66
--- /dev/null
+++ b/repos/os/src/test/audio_out_click/main.cc
@@ -0,0 +1,160 @@
+/*
+ * \brief Audio-out test implementation
+ * \author Sebastian Sumpf
+ * \author Christian Helmuth
+ * \date 2009-12-03
+ *
+ * The test program plays several tracks simultaneously to the Audio_out
+ * service. See README for the configuration.
+ */
+
+/*
+ * Copyright (C) 2009-2013 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+using namespace Genode;
+using namespace Audio_out;
+
+static const bool verbose = false;
+
+enum {
+ CHANNELS = 2, /* number of channels */
+ FRAME_SIZE = sizeof(float),
+ PERIOD_CSIZE = FRAME_SIZE * PERIOD, /* size of channel packet (bytes) */
+ PERIOD_FSIZE = CHANNELS * PERIOD_CSIZE, /* size of period in file (bytes) */
+};
+
+
+static const char *channel_names[] = { "front left", "front right" };
+
+
+class Click
+{
+ private:
+
+ Audio_out::Connection *_audio_out[CHANNELS];
+ char const *_base;
+ Genode::size_t _size;
+
+ public:
+
+ Click(char const *file)
+ {
+ for (int i = 0; i < CHANNELS; ++i) {
+ /* allocation signal for first channel only */
+ _audio_out[i] = new (env()->heap())
+ Audio_out::Connection(channel_names[i], i == 0);
+ _audio_out[i]->start();
+ }
+
+ Dataspace_capability ds_cap;
+
+ try {
+ Rom_connection rom(file);
+ rom.on_destruction(Rom_connection::KEEP_OPEN);
+ ds_cap = rom.dataspace();
+ _base = env()->rm_session()->attach(ds_cap);
+ } catch (...) {
+ PDBG("Error: Could not open: %s", file);
+ return;
+ }
+
+ Dataspace_client ds_client(ds_cap);
+ _size = ds_client.size();
+ }
+
+ void play()
+ {
+ PLOG("play click");
+
+ for (int i = 0; i < CHANNELS; i++)
+ _audio_out[i]->stream()->reset();
+
+ for (Genode::size_t offset = 0; offset < _size; offset += PERIOD_FSIZE) {
+
+ /*
+ * The current chunk (in number of frames of one channel)
+ * is the size of the period except at the end of the
+ * file.
+ */
+ size_t chunk = (offset + PERIOD_FSIZE > _size)
+ ? (_size - offset) / CHANNELS / FRAME_SIZE
+ : PERIOD;
+
+ Packet *p[CHANNELS];
+
+ while (true)
+ try {
+ p[0] = _audio_out[0]->stream()->alloc();
+ break;
+ } catch (Audio_out::Stream::Alloc_failed) {
+ _audio_out[0]->wait_for_alloc();
+ }
+
+ unsigned pos = _audio_out[0]->stream()->packet_position(p[0]);
+ for (int chn = 1; chn < CHANNELS; ++chn)
+ p[chn] = _audio_out[chn]->stream()->get(pos);
+
+ /* copy channel contents into sessions */
+ float *content = (float *)(_base + offset);
+ for (unsigned c = 0; c < CHANNELS * chunk; c += CHANNELS)
+ for (int i = 0; i < CHANNELS; ++i)
+ p[i]->content()[c / 2] = content[c + i];
+
+ /* handle last packet gracefully */
+ if (chunk < PERIOD) {
+ for (int i = 0; i < CHANNELS; ++i)
+ memset(p[i]->content() + chunk,
+ 0, PERIOD_CSIZE - FRAME_SIZE * chunk);
+ }
+
+ for (int i = 0; i < CHANNELS; i++)
+ _audio_out[i]->submit(p[i]);
+ }
+ }
+};
+
+int main(int argc, char **argv)
+{
+ PDBG("--- Audio_out click test ---\n");
+
+ Genode::Signal_context sig_ctx;
+ Genode::Signal_receiver sig_rec;
+
+ Genode::Signal_context_capability sig_cap = sig_rec.manage(&sig_ctx);
+
+ Input::Connection input;
+ Input::Event *ev_buf;
+
+ input.sigh(sig_cap);
+ ev_buf = static_cast(Genode::env()->rm_session()->attach(input.dataspace()));
+
+ Click click("click.raw");
+
+ for (;;) {
+ Genode::Signal sig = sig_rec.wait_for_signal();
+
+ for (int i = 0, num_ev = input.flush(); i < num_ev; ++i) {
+ Input::Event &ev = ev_buf[i];
+ if (ev.type() == Input::Event::PRESS) {
+ click.play();
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/repos/os/src/test/audio_out_click/target.mk b/repos/os/src/test/audio_out_click/target.mk
new file mode 100644
index 0000000000..d731cef59a
--- /dev/null
+++ b/repos/os/src/test/audio_out_click/target.mk
@@ -0,0 +1,3 @@
+TARGET = test-audio_out_click
+SRC_CC = main.cc
+LIBS = base config