diff --git a/os/include/audio_session/audio_session.h b/os/include/audio_session/audio_session.h
new file mode 100644
index 000000000..0f6675a20
--- /dev/null
+++ b/os/include/audio_session/audio_session.h
@@ -0,0 +1,330 @@
+/*
+ * \brief Audio_out session interface
+ * \author Sebastian Sumpf
+ * \date 2012-12-20
+ *
+ * An audio session corresponds to one output channel, which can be used to send
+ * audio frames. Each session consists of an 'Audio_out::Stream' object that resides
+ * in shared memory between the client and the server. The 'Audio_out::Stream' in
+ * turn consists of 'Audio_out::Packet's that contain the actual frames. Each packet
+ * within a stream is freely accessible or may be allocated successively. Also
+ * there is a current position pointer for each stream that is updated by the
+ * server. This way it is possible to send one time events that need immediate
+ * processing as well as streams that rely on buffering.
+ *
+ * Audio_out channel identifiers (loosely related to WAV channels) are:
+ *
+ * * front left (or left), front right (or right), front center
+ * * lfe (low frequency effects, subwoofer)
+ * * rear left, rear right, rear center
+ *
+ * For example, consumer-oriented 6-channel (5.1) audio uses front
+ * left/right/center, rear left/right and lfe.
+ *
+ * Note: That most components right now only support: "(front) left" and
+ * "(front) right".
+ *
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _INCLUDE__AUDIO_SESSION__AUDIO_SESSION_H_
+#define _INCLUDE__AUDIO_SESSION__AUDIO_SESSION_H_
+
+#include
+#include
+#include
+#include
+
+namespace Audio_out {
+ class Packet;
+ class Stream;
+ class Session;
+
+ enum {
+ QUEUE_SIZE = 16, /* buffer queue size */
+ PERIOD = 2048, /* samples per period */
+ SAMPLE_RATE = 44100,
+ SAMPLE_SIZE = sizeof(float),
+ };
+}
+
+/**
+ * Audio_out packet containing frames
+ */
+class Audio_out::Packet
+{
+ private:
+
+ friend class Session_client;
+ friend class Stream;
+
+ bool _valid;
+ bool _wait_for_play;
+ float _data[PERIOD];
+
+ void _submit() { _valid = true; _wait_for_play = true; }
+ void _alloc() { _wait_for_play = false; _valid = false; }
+
+ public:
+
+ Packet() : _valid(false), _wait_for_play(false) { }
+
+ /**
+ * Copy data into packet, if there are less frames given than 'PERIOD',
+ * then the remainder is filled with zeros
+ *
+ * \param data frames to copy in
+ * \param size number of frames to copy
+ */
+ void content(float *data, Genode::size_t samples)
+ {
+ Genode::memcpy(_data, data, (samples > PERIOD ? PERIOD : samples) * SAMPLE_SIZE);
+
+ if (samples < PERIOD)
+ Genode::memset(data + samples, 0, (PERIOD - samples) * SAMPLE_SIZE);
+ }
+
+ /**
+ * Get content
+ *
+ * \return pointer to frame data
+ */
+ float *content() { return _data; }
+
+ /**
+ * Play state
+ *
+ * \return true if the packet has been played back; false otherwise
+ */
+ bool played() const { return !_wait_for_play; }
+
+ /**
+ * Valid state
+ *
+ * The valid state of a packet describes that the packet has been
+ * processed by the server, it may not have been played back if the packet
+ * is invalid. For example if a server is some filter, the audio may not
+ * have been processed by the audio output driver.
+ *
+ * \return true packet has *not* been processed yet; false otherwise
+ */
+ bool valid() const { return _valid; }
+ Genode::size_t size() const { return sizeof(_data); }
+
+
+ /**********************************************
+ ** Intended to be called by the server side **
+ **********************************************/
+
+ /**
+ * Invalidate packet thus marking it as processed
+ */
+ void invalidate() { _valid = false; }
+
+ /**
+ * Mark a packet as played
+ */
+ void mark_as_played() { _wait_for_play = false; }
+};
+
+
+/**
+ * The audio stream object containing packets
+ *
+ * The stream object is created upon session creation. The server will
+ * allocate a dataspace on the clients account, the client session will then request this
+ * dataspace as well and both will attach it in there protection domains.
+ * After that the stream pointer within a session will be pointed to the
+ * attached dataspace on both sides. Therefore the constructor of the 'Stream'
+ * object will never be called.
+ */
+class Audio_out::Stream
+{
+ private:
+
+ unsigned _pos; /* current playback position */
+ unsigned _tail; /* tail pointer used for allocations */
+ Packet _buf[QUEUE_SIZE]; /* packet queue */
+
+ public:
+
+ /**
+ * Exceptions
+ */
+ class Alloc_failed { };
+
+ /**
+ * Current audio playback position
+ *
+ * \return position
+ */
+ unsigned pos() const { return _pos; }
+
+
+ /**
+ * Retrieve next packet for given packet
+ *
+ * \param packet preceding packet
+ *
+ * \return Successor of packet or successor of current position if
+ * 'packet' is zero
+ */
+ Packet *next(Packet *packet = 0)
+ {
+ return packet ? get(packet_position(packet) + 1) : get(pos() + 1);
+ }
+
+ /**
+ * Retrieves the position of a given packet in the stream queue
+ *
+ * \param packet a packet
+ *
+ * \return position in stream queue
+ */
+ unsigned packet_position(Packet *packet) { return packet - &_buf[0]; }
+
+
+ /**
+ * Check if stream queue is full/empty
+ */
+ bool empty() const
+ {
+ bool valid = false;
+ for (int i = 0; i < QUEUE_SIZE; i++)
+ valid |= _buf[i].valid();
+
+ return !valid;
+ }
+
+ bool full() const { return (_tail + 1) % QUEUE_SIZE == _pos; }
+
+
+ /**
+ * Retrieve an audio at given position
+ *
+ * \param pos position in stream
+ *
+ * \retun Audio_out packet
+ */
+ Packet *get(unsigned pos) { return &_buf[pos % QUEUE_SIZE]; }
+
+
+ /**
+ * Allocate a packet in stream
+ *
+ * \return Packet
+ * \throw Alloc_failed when stream queue is full
+ */
+ Packet *alloc()
+ {
+ if (full())
+ throw Alloc_failed();
+
+ unsigned pos = _tail;
+ _tail = (_tail + 1) % QUEUE_SIZE;
+
+ Packet *p = get(pos);
+ p->_alloc();
+
+ return p;
+ }
+
+ /**
+ * Reset stream queue, this means that allocation will start at current
+ * queue position
+ */
+ void reset() { _tail = _pos; }
+
+
+ /**********************************************
+ ** Intended to be called by the server side **
+ ***********************************************/
+
+ /**
+ * Set current stream position
+ *
+ * \param pos current position
+ */
+ void pos(unsigned p) { _pos = p; }
+
+ /**
+ * Increment current stream position by one
+ */
+ void increment_position() { _pos = (_pos + 1) % QUEUE_SIZE; }
+};
+
+
+/**
+ * Audio_out session base
+ */
+class Audio_out::Session : public Genode::Session
+{
+ protected:
+
+ Stream *_stream;
+
+ public:
+
+ static const char *service_name() { return "Audio_out"; }
+
+ /**
+ * Return stream of this session, see 'Stream' above
+ */
+ Stream *stream() const { return _stream; }
+
+ /**
+ * Start playback (alloc and submit packets after calling 'start')
+ */
+ virtual void start() = 0;
+
+ /**
+ * Stop playback
+ */
+ virtual void stop() = 0;
+
+
+ /*************
+ ** Signals **
+ *************/
+
+
+ /**
+ * The 'progress' signal may be sent from the server to the client if a
+ * packet has been played.
+ *
+ * See: client.h, connection.h
+ */
+ virtual void progress_sigh(Genode::Signal_context_capability sigh) = 0;
+
+ /**
+ * The 'alloc' signal may be sent from the server to the client when the
+ * stream queue leaves the 'full' state.
+ *
+ * See: client.h, connection.h
+ */
+ virtual void alloc_sigh(Genode::Signal_context_capability sigh) = 0;
+
+ /**
+ * The 'data_avail' signal is sent from the client to the surfer the
+ * stream queue leaves the 'empty' state.
+ */
+ virtual Genode::Signal_context_capability data_avail_sigh() = 0;
+
+ GENODE_RPC(Rpc_start, void, start);
+ GENODE_RPC(Rpc_stop, void, stop);
+ GENODE_RPC(Rpc_dataspace, Genode::Dataspace_capability, dataspace);
+ GENODE_RPC(Rpc_progress_sigh, void, progress_sigh, Genode::Signal_context_capability);
+ GENODE_RPC(Rpc_alloc_sigh, void, alloc_sigh, Genode::Signal_context_capability);
+ GENODE_RPC(Rpc_data_avail_sigh, Genode::Signal_context_capability, data_avail_sigh);
+
+ GENODE_RPC_INTERFACE(Rpc_start, Rpc_stop, Rpc_dataspace, Rpc_progress_sigh,
+ Rpc_alloc_sigh, Rpc_data_avail_sigh);
+};
+
+#endif /* _INCLUDE__AUDIO_SESSION__AUDIO_SESSION_H_ */
diff --git a/os/include/audio_session/client.h b/os/include/audio_session/client.h
new file mode 100644
index 000000000..1e5280f1e
--- /dev/null
+++ b/os/include/audio_session/client.h
@@ -0,0 +1,147 @@
+/**
+ * \brief Audio_out-session-client side
+ * \author Sebastian Sumpf
+ * \date 2012-12-20
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _INCLUDE__AUDIO_SESSEN__CLIENT_H_
+#define _INCLUDE__AUDIO_SESSEN__CLIENT_H_
+
+#include
+#include
+#include
+
+namespace Audio_out {
+ struct Signal;
+ struct Session_client;
+}
+
+
+struct Audio_out::Signal
+{
+ Genode::Signal_receiver recv;
+ Genode::Signal_context context;
+ Genode::Signal_context_capability cap;
+
+ Signal() : cap(recv.manage(&context)) { }
+
+ void wait() { recv.wait_for_signal(); }
+};
+
+
+class Audio_out::Session_client : public Genode::Rpc_client
+{
+ private:
+
+ Signal _progress;
+ Signal _alloc;
+
+ Genode::Signal_transmitter _data_avail;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param session session capability
+ * \param alloc_signal true, install 'alloc_signal' receiver
+ * \param progress_signal true, install 'progress_signal' receiver
+ */
+ Session_client(Genode::Capability session, bool alloc_signal, bool progress_signal)
+ :
+ Genode::Rpc_client(session),
+ _data_avail(call())
+ {
+ /* ask server for stream data space and attach it */
+ _stream = static_cast(Genode::env()->rm_session()->attach(call()));
+
+ if (progress_signal)
+ progress_sigh(_progress.cap);
+
+ if (alloc_signal)
+ alloc_sigh(_alloc.cap);
+
+ }
+
+
+ /*************
+ ** Signals **
+ *************/
+
+ void progress_sigh(Genode::Signal_context_capability sigh) { call(sigh); }
+ void alloc_sigh(Genode::Signal_context_capability sigh) { call(sigh); }
+
+ Genode::Signal_context_capability data_avail_sigh() {
+ return Genode::Signal_context_capability(); }
+
+
+ /***********************
+ ** Session interface **
+ ***********************/
+
+ void start()
+ {
+ call();
+
+ /* reset tail pointer */
+ stream()->reset();
+ }
+
+ void stop() { call(); }
+
+
+ /**********************************
+ ** Session interface extensions **
+ **********************************/
+
+ /**
+ * Wait for progress signal
+ */
+ void wait_for_progress()
+ {
+ if (!_progress.cap.valid()) {
+ PWRN("Progress signal is not installed, will not block "
+ "(enable in 'Audio_out::Connection')");
+ return;
+ }
+
+ _progress.wait();
+ }
+
+ /**
+ * Wait for allocation signal. This can be used when the 'Stream' is full
+ * and the applications want for block until the stream has free elements
+ * again.
+ */
+ void wait_for_alloc()
+ {
+ if (!_alloc.cap.valid()) {
+ PWRN("Alloc signal is not installed, will not block "
+ "(enable in 'Audio_out::Connection')");
+ return;
+ }
+
+ _alloc.wait();
+ }
+
+ /**
+ * Submit a packet
+ */
+ void submit(Packet *packet)
+ {
+ bool empty = stream()->empty();
+
+ packet->_submit();
+ if (empty)
+ _data_avail.submit();
+ }
+};
+
+#endif /* _INCLUDE__AUDIO_SESSEN__CLIENT_H_ */
diff --git a/os/include/audio_session/connection.h b/os/include/audio_session/connection.h
new file mode 100644
index 000000000..cde360eaf
--- /dev/null
+++ b/os/include/audio_session/connection.h
@@ -0,0 +1,51 @@
+/*
+ * \brief Connection to audio service
+ * \author Sebastian Sumpf
+ * \date 2012-12-20
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _INCLUDE__AUDIO_SESSION__CONNECTION_H_
+#define _INCLUDE__AUDIO_SESSION__CONNECTION_H_
+
+#include
+#include
+#include
+
+
+namespace Audio_out {
+ struct Connection;
+}
+
+
+struct Audio_out::Connection : Genode::Connection, Audio_out::Session_client
+{
+ /**
+ * Constructor
+ *
+ * \param channel channel identifier (e.g., "front left")
+ * \param alloc_signal install 'alloc_signal', the client may thean use
+ * 'wait_for_alloc' when the stream is full
+ * \param progress_signal install progress signal, the client may then call
+ * 'wait_for_progress' which is send when the server
+ * processed one or more packets
+ */
+ Connection(const char *channel,
+ bool alloc_signal = true,
+ bool progress_signal = false)
+ :
+ Genode::Connection(
+ session("ram_quota=%zd, channel=\"%s\"",
+ 2*4096 + sizeof(Stream), channel)),
+ Session_client(cap(), alloc_signal, progress_signal)
+ { }
+};
+
+
+#endif /* _INCLUDE__AUDIO_SESSION__CONNECTION_H_ */
diff --git a/os/include/audio_session/rpc_object.h b/os/include/audio_session/rpc_object.h
new file mode 100644
index 000000000..722a57402
--- /dev/null
+++ b/os/include/audio_session/rpc_object.h
@@ -0,0 +1,124 @@
+/*
+ * \brief Server side audio-session interface
+ * \author Sebastian Sumpf
+ * \date 2012-12-10
+ */
+
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef _INCLUDE__AUDIO_SESSION__RPC_OBJECT_H_
+#define _INCLUDE__AUDIO_SESSION__RPC_OBJECT_H_
+
+#include
+#include
+#include
+
+
+namespace Audio_out {
+ class Session_rpc_object;
+}
+
+
+class Audio_out::Session_rpc_object : public Genode::Rpc_object
+{
+ protected:
+
+ bool _stopped; /* state */
+ Genode::Ram_dataspace_capability _ds; /* contains Audio_out_stream */
+ Genode::Signal_transmitter _progress;
+ Genode::Signal_transmitter _alloc;
+
+ Genode::Signal_context_capability _data_cap;
+
+ bool _progress_sigh; /* progress signal on/off */
+ bool _alloc_sigh; /* alloc signal on/off */
+
+ public:
+
+ Session_rpc_object(Genode::Signal_context_capability data_cap)
+ :
+ _stopped(true), _data_cap(data_cap),
+ _progress_sigh(false), _alloc_sigh(false)
+ {
+ _ds = Genode::env()->ram_session()->alloc(sizeof(Stream));
+ _stream = static_cast(Genode::env()->rm_session()->attach(_ds));
+ }
+
+ virtual ~Session_rpc_object()
+ {
+ if (_ds.valid()) {
+ Genode::env()->rm_session()->detach(_stream);
+ Genode::env()->ram_session()->free(_ds);
+ }
+ }
+
+ /**************
+ ** Signals **
+ **************/
+
+ void progress_sigh(Genode::Signal_context_capability sigh)
+ {
+ _progress.context(sigh);
+ _progress_sigh = true;
+ }
+
+ Genode::Signal_context_capability data_avail_sigh() {
+ return _data_cap; }
+
+ void alloc_sigh(Genode::Signal_context_capability sigh)
+ {
+ _alloc.context(sigh);
+ _alloc_sigh = true;
+ }
+
+
+ /***********************
+ ** Session interface **
+ ***********************/
+
+ void start() { _stopped = false; }
+ void stop() { _stopped = true; }
+
+ Genode::Dataspace_capability dataspace() { return _ds; }
+
+
+ /**********************************
+ ** Session interface extensions **
+ **********************************/
+
+ /**
+ * Send 'progress' signal
+ */
+ void progress_submit()
+ {
+ if (_progress_sigh)
+ _progress.submit();
+ }
+
+ /**
+ * Send 'alloc' signal
+ */
+ void alloc_submit()
+ {
+ if (_alloc_sigh)
+ _alloc.submit();
+ }
+
+ /**
+ * Return true if client state is stopped
+ */
+ bool stopped() const { return _stopped; }
+
+ /**
+ * Return true if client session is active
+ */
+ bool active() const { return !_stopped; }
+};
+
+#endif /* _INCLUDE__AUDIO_SESSION__RPC_OBJECT_H_ */