diff --git a/dde_oss/src/drivers/oss/main.cc b/dde_oss/src/drivers/oss/main.cc index f0d624467..8be1fc013 100644 --- a/dde_oss/src/drivers/oss/main.cc +++ b/dde_oss/src/drivers/oss/main.cc @@ -19,7 +19,7 @@ extern "C" { #include #include #include -#include +#include #include #include diff --git a/libports/src/lib/sdl/audio/SDL_genodeaudio.cc b/libports/src/lib/sdl/audio/SDL_genodeaudio.cc index fbbad5022..5cff4c528 100644 --- a/libports/src/lib/sdl/audio/SDL_genodeaudio.cc +++ b/libports/src/lib/sdl/audio/SDL_genodeaudio.cc @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include diff --git a/os/include/audio_out_session/audio_out_session.h b/os/include/audio_out_session/audio_out_session.h index 0bce70d0a..d5d1ecca8 100644 --- a/os/include/audio_out_session/audio_out_session.h +++ b/os/include/audio_out_session/audio_out_session.h @@ -1,31 +1,33 @@ /* - * \brief Audio-out session interface - * \author Norman Feske + * \brief Audio_out session interface * \author Sebastian Sumpf - * \author Christian Helmuth - * \author Stefan Kalkowski - * \date 2009-12-02 + * \date 2012-12-20 * - * A audio-out session corresponds to one output channel, which can be used to - * transmit audio frames. Payload is communicated over the packet-stream - * interface set up between 'Session_client' and 'Session_server'. The term - * _channel_ means literally one audio channel, e.g. front left or rear center. - * Therefore, a standard two-channel stereo track needs two audio-out sessions - * - one for "front left" and one for "front right". The channel format is - * FLOAT_LE currently. + * 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 + * sporadic events that need immediate processing as well as streams that rely + * on buffering. * - * Audio channel identifiers (loosly related to WAV channels) are: + * Audio_out channel identifiers (loosely related to WAV channels) are: * - * * Front left, right, center - * * LFE (low frequency effets, subwoofer) - * * Rear left, right, center + * * 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. + * left/right/center, rear left/right and lfe. + * + * Note: That most components right now only support: "(front) left" and + * "(front) right". */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2012-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. @@ -34,65 +36,295 @@ #ifndef _INCLUDE__AUDIO_OUT_SESSION__AUDIO_OUT_SESSION_H_ #define _INCLUDE__AUDIO_OUT_SESSION__AUDIO_OUT_SESSION_H_ -#include -#include +#include #include -#include -#include +#include #include + namespace Audio_out { + class Packet; + class Stream; + class Session; enum { - QUEUE_SIZE = 16, /* buffer queue size */ - FRAME_SIZE = 4, /* frame size in bytes */ - PERIOD = 1024 /* frames per period */ - }; - - struct Session : Genode::Session - { - typedef Packet_stream_policy Policy; - - typedef Packet_stream_tx::Channel Channel; - - static const char *service_name() { return "Audio_out"; } - - virtual ~Session() { } - - /** - * Request client-side packet-stream interface of channel - */ - virtual Channel::Source *stream() { return 0; } - - /** - * Flush the audio buffer - */ - virtual void flush(void) = 0; - - /** - * Set synchronization session - * - * \param audio_out_session synchronization session - * - * Session can be kept in sync (or bundled) using this function, for - * example, the left and right stero channels. A session has exactly - * one synchronization session. - */ - virtual void sync_session(Session_capability audio_out_session) = 0; - - - /******************* - ** RPC interface ** - *******************/ - - GENODE_RPC(Rpc_flush, void, flush); - GENODE_RPC(Rpc_sync_session, void, sync_session, Session_capability); - GENODE_RPC(Rpc_channel_cap, Genode::Capability, channel_cap); - - GENODE_RPC_INTERFACE(Rpc_flush, Rpc_sync_session, Rpc_channel_cap); + 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', + * 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 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 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 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_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 + * + * \return 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 is 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 is 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 server 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_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_OUT_SESSION__AUDIO_OUT_SESSION_H_ */ diff --git a/os/include/audio_out_session/capability.h b/os/include/audio_out_session/capability.h index 3f70b605f..5633ee437 100644 --- a/os/include/audio_out_session/capability.h +++ b/os/include/audio_out_session/capability.h @@ -25,6 +25,7 @@ namespace Audio_out { * because this file relies on the 'Audio_out::Session_capability' type. */ class Session; - typedef Genode::Capability Session_capability; } + typedef Genode::Capability Session_capability; +} #endif /* _INCLUDE__AUDIO_OUT_SESSION__CAPABILITY_H_ */ diff --git a/os/include/audio_out_session/client.h b/os/include/audio_out_session/client.h index 6ecb02b07..90bcea069 100644 --- a/os/include/audio_out_session/client.h +++ b/os/include/audio_out_session/client.h @@ -1,14 +1,11 @@ /* - * \brief Client-side audio-out session interface - * \author Norman Feske + * \brief Client-side Audio_out-session * \author Sebastian Sumpf - * \author Christian Helmuth - * \author Stefan Kalkowski - * \date 2009-12-02 + * \date 2012-12-20 */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2012-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. @@ -17,58 +14,138 @@ #ifndef _INCLUDE__AUDIO_OUT_SESSION__CLIENT_H_ #define _INCLUDE__AUDIO_OUT_SESSION__CLIENT_H_ +#include #include #include -#include namespace Audio_out { - - class Session_client : public Genode::Rpc_client - { - private: - - Packet_stream_tx::Client _channel; - - Session_capability _cap; - - public: - - /** - * Constructor - * - * \param session Audio-out session capability - * \param buffer_alloc allocator used for managing the - * transmission buffer - */ - Session_client(Genode::Capability session, - Genode::Range_allocator *buffer_alloc) - : - Genode::Rpc_client(session), - _channel(call(), buffer_alloc), - _cap(session) - { } - - /** - * Return session capability of this session - * - * This function is meant to be used to obtain the argument for the - * 'sync_session' function called for another 'Audio_out' session. - */ - Session_capability session_capability() { return _cap; } - - Session::Channel *channel() { return &_channel; } - - /********************************* - ** Audio-out session interface ** - *********************************/ - - Session::Channel::Source *stream() { return _channel.source(); } - - void flush(void) { call(); } - - void sync_session(Session_capability audio_out_session) { - call(audio_out_session); } - }; + 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 application wants + * to 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_OUT_SESSION__CLIENT_H_ */ diff --git a/os/include/audio_out_session/connection.h b/os/include/audio_out_session/connection.h index f4f3b40d9..b320f0712 100644 --- a/os/include/audio_out_session/connection.h +++ b/os/include/audio_out_session/connection.h @@ -1,13 +1,11 @@ /* - * \brief Connection to audio-out service - * \author Norman Feske + * \brief Connection to audio service * \author Sebastian Sumpf - * \author Christian Helmuth - * \date 2009-12-01 + * \date 2012-12-20 */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2012-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. @@ -20,30 +18,33 @@ #include #include -namespace Audio_out { - struct Connection : Genode::Connection, Session_client - { - /** - * Constructor - * - * \param channel channel identifier (e.g., "front left") - * \param buffer_alloc allocator used for managing the - * transmission buffer - * \param buffer_size size of transmission buffer in bytes - * (defaults to all packets of the queue plus - * some space for metadata) - */ - Connection(const char *channel, - Genode::Range_allocator *buffer_alloc, - Genode::size_t buffer_size = QUEUE_SIZE * FRAME_SIZE * PERIOD + 0x400) - : - Genode::Connection( - session("ram_quota=%zd, channel=\"%s\", buffer_size=%zd", - 3*4096 + buffer_size, channel, buffer_size)), - Session_client(cap(), buffer_alloc) - { } - }; +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 then 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 sent 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_OUT_SESSION__CONNECTION_H_ */ diff --git a/os/include/audio_out_session/rpc_object.h b/os/include/audio_out_session/rpc_object.h index a78740ac4..7c61651be 100644 --- a/os/include/audio_out_session/rpc_object.h +++ b/os/include/audio_out_session/rpc_object.h @@ -1,14 +1,11 @@ /* - * \brief Server-side audio-out session interface - * \author Norman Feske + * \brief Server-side audio-session interface * \author Sebastian Sumpf - * \author Christian Helmuth - * \author Stefan Kalkowski - * \date 2009-12-02 + * \date 2012-12-10 */ /* - * Copyright (C) 2009-2013 Genode Labs GmbH + * Copyright (C) 2012-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. @@ -17,41 +14,112 @@ #ifndef _INCLUDE__AUDIO_OUT_SESSION__RPC_OBJECT_H_ #define _INCLUDE__AUDIO_OUT_SESSION__RPC_OBJECT_H_ +#include #include #include -#include + namespace Audio_out { - - class Session_rpc_object : public Genode::Rpc_object - { - protected: - - Packet_stream_tx::Rpc_object _channel; - - public: - - /** - * Constructor - * - * \param ds dataspace used as communication buffer - * for the packet stream - * \param ep entry point used for packet-stream channel - */ - Session_rpc_object(Genode::Dataspace_capability ds, - Genode::Rpc_entrypoint &ep) - : _channel(ds, ep) { } - - /** - * Return capability to packet-stream channel - * - * This function is called by the client via an RPC call at session - * construction time. - */ - Genode::Capability channel_cap() { return _channel.cap(); } - - Channel::Sink *channel() { return _channel.sink(); } - }; + 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_OUT_SESSION__RPC_OBJECT_H_ */ diff --git a/os/include/audio_session/audio_session.h b/os/include/audio_session/audio_session.h deleted file mode 100644 index 0f6675a20..000000000 --- a/os/include/audio_session/audio_session.h +++ /dev/null @@ -1,330 +0,0 @@ -/* - * \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 deleted file mode 100644 index 1e5280f1e..000000000 --- a/os/include/audio_session/client.h +++ /dev/null @@ -1,147 +0,0 @@ -/** - * \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 deleted file mode 100644 index cde360eaf..000000000 --- a/os/include/audio_session/connection.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * \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 deleted file mode 100644 index 722a57402..000000000 --- a/os/include/audio_session/rpc_object.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * \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_ */ diff --git a/os/src/drivers/audio_out/linux/main.cc b/os/src/drivers/audio_out/linux/main.cc index 2d98162de..15bac4fbf 100644 --- a/os/src/drivers/audio_out/linux/main.cc +++ b/os/src/drivers/audio_out/linux/main.cc @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include "alsa.h" diff --git a/os/src/server/mixer/mixer.cc b/os/src/server/mixer/mixer.cc index 9df8df353..b615424ff 100644 --- a/os/src/server/mixer/mixer.cc +++ b/os/src/server/mixer/mixer.cc @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include #include diff --git a/os/src/test/audio_out/main.cc b/os/src/test/audio_out/main.cc index 090081825..c1cf639e1 100644 --- a/os/src/test/audio_out/main.cc +++ b/os/src/test/audio_out/main.cc @@ -15,7 +15,7 @@ * under the terms of the GNU General Public License version 2. */ -#include +#include #include #include #include