diff --git a/repos/os/include/audio_in_session/audio_in_session.h b/repos/os/include/audio_in_session/audio_in_session.h
new file mode 100644
index 000000000..c4d42effd
--- /dev/null
+++ b/repos/os/include/audio_in_session/audio_in_session.h
@@ -0,0 +1,328 @@
+/*
+ * \brief Audio_in session interface
+ * \author Josef Soentgen
+ * \date 2015-05-08
+ *
+ * An Audio_in session corresponds to one input channel, which can be used to
+ * receive audio frames. Each session consists of an 'Audio_in::Stream' object
+ * that resides in shared memory between the client and the server. The
+ * 'Audio_in::Stream' in turn consists of 'Audio_in::Packet's that contain
+ * the actual frames. Each packet within a stream is freely accessible. When
+ * recording the source will allocate a new packet and override already
+ * recorded ones if the queue is already full. In contrast to the
+ * 'Audio_out::Stream' the current position pointer is updated by the client.
+ */
+
+/*
+ * Copyright (C) 2015 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_IN_SESSION__AUDIO_IN_SESSION_H_
+#define _INCLUDE__AUDIO_IN_SESSION__AUDIO_IN_SESSION_H_
+
+#include
+#include
+#include
+#include
+
+
+namespace Audio_in {
+ class Packet;
+ class Stream;
+ class Session;
+
+ enum {
+ QUEUE_SIZE = 431, /* buffer queue size (~5s) */
+ PERIOD = 512, /* samples per periode (~11.6ms) */
+ SAMPLE_RATE = 44100,
+ SAMPLE_SIZE = sizeof(float),
+ };
+}
+
+
+/**
+ * Audio_in packet containing frames
+ */
+class Audio_in::Packet
+{
+ private:
+
+ friend class Session_client;
+ friend class Stream;
+
+ bool _valid;
+ bool _wait_for_record;
+ float _data[PERIOD];
+
+ void _submit() { _valid = true; _wait_for_record = true; }
+ void _alloc() { _wait_for_record = false; _valid = false; }
+
+ public:
+
+ Packet() : _valid(false), _wait_for_record(false) { }
+
+ /**
+ * Copy data into packet, if there are less frames given than 'PERIOD',
+ * 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; }
+
+ /**
+ * Record state
+ *
+ * \return true if the packet has been recorded; false otherwise
+ */
+ bool recorded() const { return !_wait_for_record; }
+
+ /**
+ * Valid state
+ *
+ * The valid state of a packet describes that the packet has been
+ * processed by the server even though it may not have been played back
+ * if the packet is invalid. For example, if a server is a filter, the
+ * audio may not have been processed by the output driver.
+ *
+ * \return true if 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 recorded
+ */
+ void mark_as_recorded() { _wait_for_record = false; }
+};
+
+
+/**
+ * The audio-stream object containing packets
+ *
+ * The stream object is created upon session creation. The server will allocate
+ * a dataspace on the client's account. The client session will then request
+ * this dataspace and both client and server will attach it in their respective
+ * protection domain. After that, the stream pointer within a session will be
+ * pointed to the attached dataspace on both sides. Because the 'Stream' object
+ * is backed by shared memory, its constructor is never supposed to be called.
+ */
+class Audio_in::Stream
+{
+ private:
+
+ unsigned _pos { 0 }; /* current record position */
+ unsigned _tail { 0 }; /* tail pointer used for allocations */
+ Packet _buf[QUEUE_SIZE]; /* packet queue */
+
+ public:
+
+ /**
+ * Current audio record position
+ *
+ * \return position
+ */
+ unsigned pos() const { return _pos; }
+
+ /**
+ * Current tail position
+ *
+ * \return tail position
+ */
+ unsigned tail() const { return _tail; }
+
+ /**
+ * 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 empty
+ */
+ bool empty() const
+ {
+ bool valid = false;
+ for (int i = 0; i < QUEUE_SIZE; i++)
+ valid |= _buf[i].valid();
+
+ return !valid;
+ }
+
+ /**
+ * Retrieve an packet at given position
+ *
+ * \param pos position in stream
+ *
+ * \return Audio_in packet
+ */
+ Packet *get(unsigned pos) { return &_buf[pos % QUEUE_SIZE]; }
+
+ /**
+ * Allocate a packet in stream
+ *
+ * \return Packet
+ */
+ Packet *alloc()
+ {
+ 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 **
+ **********************************************/
+
+ /**
+ * Submit a packet to the packet queue
+ */
+ void submit(Packet *p) { p->_submit(); }
+
+ /**
+ * Check if stream queue has overrun
+ */
+ bool overrun() const { return (_tail + 1) % QUEUE_SIZE == _pos; }
+
+
+ /**********************************************
+ ** Intended to be called by the client 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_in session base
+ */
+class Audio_in::Session : public Genode::Session
+{
+ protected:
+
+ Stream *_stream;
+
+ public:
+
+ static const char *service_name() { return "Audio_in"; }
+
+ /**
+ * Return stream of this session, see 'Stream' above
+ */
+ Stream *stream() const { return _stream; }
+
+ /**
+ * Start recording (alloc and submit packets after calling 'start')
+ */
+ virtual void start() = 0;
+
+ /**
+ * Stop recording
+ */
+ virtual void stop() = 0;
+
+
+ /*************
+ ** Signals **
+ *************/
+
+ /**
+ * The 'progress' signal is sent from the server to the client if a
+ * packet has been recorded.
+ *
+ * See: client.h, connection.h
+ */
+ virtual void progress_sigh(Genode::Signal_context_capability sigh) = 0;
+
+ /**
+ * The 'overrun' signal is sent from the server to the client if an
+ * overrun has occured.
+ *
+ * See: client.h, connection.h
+ */
+ virtual void overrun_sigh(Genode::Signal_context_capability sigh) = 0;
+
+ /**
+ * The 'data_avail' signal is sent from the server to the client if 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_overrun_sigh, void, overrun_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_overrun_sigh,
+ Rpc_data_avail_sigh);
+};
+
+#endif /* _INCLUDE__AUDIO_IN_SESSION__AUDIO_IN_SESSION_H_ */
diff --git a/repos/os/include/audio_in_session/capability.h b/repos/os/include/audio_in_session/capability.h
new file mode 100644
index 000000000..d7849f7cc
--- /dev/null
+++ b/repos/os/include/audio_in_session/capability.h
@@ -0,0 +1,29 @@
+/*
+ * \brief Audio-in session capability type
+ * \author Josef Soentgen
+ * \date 2015-05-08
+ */
+
+/*
+ * Copyright (C) 2015 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_IN_SESSION__CAPABILITY_H_
+#define _INCLUDE__AUDIO_IN_SESSION__CAPABILITY_H_
+
+#include
+
+namespace Audio_in {
+
+ /*
+ * We cannot include 'audio_in_session/audio_in_session.h'
+ * because this file relies on the 'Audio_in::Session_capability' type.
+ */
+ class Session;
+ typedef Genode::Capability Session_capability;
+}
+
+#endif /* _INCLUDE__AUDIO_IN_SESSION__CAPABILITY_H_ */
diff --git a/repos/os/include/audio_in_session/client.h b/repos/os/include/audio_in_session/client.h
new file mode 100644
index 000000000..1367d76b4
--- /dev/null
+++ b/repos/os/include/audio_in_session/client.h
@@ -0,0 +1,119 @@
+/*
+ * \brief Client-side Audio_in-session
+ * \author Josef Soentgen
+ * \date 2015-05-08
+ */
+
+/*
+ * Copyright (C) 2015 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_IN_SESSION__CLIENT_H_
+#define _INCLUDE__AUDIO_IN_SESSION__CLIENT_H_
+
+/* Genode includes */
+#include
+#include
+#include
+
+
+namespace Audio_in {
+ struct Signal;
+ struct Session_client;
+}
+
+
+struct Audio_in::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_in::Session_client : public Genode::Rpc_client
+{
+ private:
+
+ Signal _progress;
+
+ Genode::Signal_transmitter _data_avail;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param session session capability
+ * \param progress_signal true, install 'progress_signal' receiver
+ */
+ Session_client(Genode::Capability session,
+ 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);
+ }
+
+
+ /*************
+ ** Signals **
+ *************/
+
+ void progress_sigh(Genode::Signal_context_capability sigh) {
+ call(sigh); }
+
+ void overrun_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_in::Connection')");
+ return;
+ }
+
+ _progress.wait();
+ }
+};
+
+#endif /* _INCLUDE__AUDIO_IN_SESSION__CLIENT_H_ */
diff --git a/repos/os/include/audio_in_session/connection.h b/repos/os/include/audio_in_session/connection.h
new file mode 100644
index 000000000..852804ace
--- /dev/null
+++ b/repos/os/include/audio_in_session/connection.h
@@ -0,0 +1,43 @@
+/*
+ * \brief Connection to Audio_in service
+ * \author Josef Soentgen
+ * \date 2015-05-08
+ */
+
+/*
+ * Copyright (C) 2015 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_IN_SESSION__CONNECTION_H_
+#define _INCLUDE__AUDIO_IN_SESSION__CONNECTION_H_
+
+#include
+#include
+#include
+
+
+namespace Audio_in { struct Connection; }
+
+
+struct Audio_in::Connection : Genode::Connection, Audio_in::Session_client
+{
+ /**
+ * Constructor
+ *
+ * \param progress_signal install progress signal, the client may then
+ * call 'wait_for_progress', which is sent when the
+ * server processed one or more packets
+ */
+ Connection(char const *channel, bool progress_signal = false)
+ :
+ Genode::Connection(
+ session("ram_quota=%zd, channel=\"%s\"",
+ 2*4096 + sizeof(Stream), channel)),
+ Session_client(cap(), progress_signal)
+ { }
+};
+
+#endif /* _INCLUDE__AUDIO_IN_SESSION__CONNECTION_H_ */
diff --git a/repos/os/include/audio_in_session/rpc_object.h b/repos/os/include/audio_in_session/rpc_object.h
new file mode 100644
index 000000000..2034aa056
--- /dev/null
+++ b/repos/os/include/audio_in_session/rpc_object.h
@@ -0,0 +1,116 @@
+/*
+ * \brief Server-side Audio_in session interface
+ * \author Josef Soentgen
+ * \date 2015-05-08
+ */
+
+/*
+ * Copyright (C) 2015 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_IN_SESSION__RPC_OBJECT_H_
+#define _INCLUDE__AUDIO_IN_SESSION__RPC_OBJECT_H_
+
+/* Genode includes */
+#include
+#include
+#include
+
+
+namespace Audio_in { class Session_rpc_object; }
+
+
+class Audio_in::Session_rpc_object : public Genode::Rpc_object
+{
+ protected:
+
+ bool _stopped; /* state */
+ Genode::Ram_dataspace_capability _ds; /* contains Audio_in stream */
+
+ Genode::Signal_context_capability _data_cap;
+ Genode::Signal_context_capability _progress_cap;
+ Genode::Signal_context_capability _overrun_cap;
+
+ public:
+
+ Session_rpc_object(Genode::Signal_context_capability data_cap)
+ :
+ _stopped(true), _data_cap(data_cap)
+ {
+ using namespace Genode;
+
+ _ds = env()->ram_session()->alloc(sizeof(Stream));
+ _stream = static_cast(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_cap = sigh; }
+
+ void overrun_sigh(Genode::Signal_context_capability sigh) {
+ _overrun_cap = sigh; }
+
+ Genode::Signal_context_capability data_avail_sigh() {
+ return _data_cap; }
+
+
+ /***********************
+ ** 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_cap.valid())
+ Genode::Signal_transmitter(_progress_cap).submit();
+ }
+
+ /**
+ * Send 'overrun' signal
+ */
+ void overrun_submit()
+ {
+ if (_overrun_cap.valid())
+ Genode::Signal_transmitter(_overrun_cap).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_IN_SESSION__RPC_OBJECT_H_ */