mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-19 15:43:56 +00:00
committed by
Norman Feske
parent
47bb48bdd6
commit
5aea55e417
@ -19,7 +19,7 @@ extern "C" {
|
|||||||
#include <base/sleep.h>
|
#include <base/sleep.h>
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#include <audio_session/rpc_object.h>
|
#include <audio_out_session/rpc_object.h>
|
||||||
#include <util/misc_math.h>
|
#include <util/misc_math.h>
|
||||||
|
|
||||||
#include <audio.h>
|
#include <audio.h>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
#include <base/allocator_avl.h>
|
#include <base/allocator_avl.h>
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
#include <base/thread.h>
|
#include <base/thread.h>
|
||||||
#include <audio_session/connection.h>
|
#include <audio_out_session/connection.h>
|
||||||
#include <os/config.h>
|
#include <os/config.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,31 +1,33 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Audio-out session interface
|
* \brief Audio_out session interface
|
||||||
* \author Norman Feske
|
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
* \author Christian Helmuth
|
* \date 2012-12-20
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2009-12-02
|
|
||||||
*
|
*
|
||||||
* A audio-out session corresponds to one output channel, which can be used to
|
* An audio session corresponds to one output channel, which can be used to
|
||||||
* transmit audio frames. Payload is communicated over the packet-stream
|
* send audio frames. Each session consists of an 'Audio_out::Stream' object
|
||||||
* interface set up between 'Session_client' and 'Session_server'. The term
|
* that resides in shared memory between the client and the server. The
|
||||||
* _channel_ means literally one audio channel, e.g. front left or rear center.
|
* 'Audio_out::Stream' in turn consists of 'Audio_out::Packet's that contain
|
||||||
* Therefore, a standard two-channel stereo track needs two audio-out sessions
|
* the actual frames. Each packet within a stream is freely accessible or may
|
||||||
* - one for "front left" and one for "front right". The channel format is
|
* be allocated successively. Also there is a current position pointer for each
|
||||||
* FLOAT_LE currently.
|
* 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
|
* * front left (or left), front right (or right), front center
|
||||||
* * LFE (low frequency effets, subwoofer)
|
* * lfe (low frequency effects, subwoofer)
|
||||||
* * Rear left, right, center
|
* * rear left, rear right, rear center
|
||||||
*
|
*
|
||||||
* For example, consumer-oriented 6-channel (5.1) audio uses front
|
* 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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -34,65 +36,295 @@
|
|||||||
#ifndef _INCLUDE__AUDIO_OUT_SESSION__AUDIO_OUT_SESSION_H_
|
#ifndef _INCLUDE__AUDIO_OUT_SESSION__AUDIO_OUT_SESSION_H_
|
||||||
#define _INCLUDE__AUDIO_OUT_SESSION__AUDIO_OUT_SESSION_H_
|
#define _INCLUDE__AUDIO_OUT_SESSION__AUDIO_OUT_SESSION_H_
|
||||||
|
|
||||||
#include <base/signal.h>
|
#include <base/allocator.h>
|
||||||
#include <base/rpc.h>
|
|
||||||
#include <dataspace/capability.h>
|
#include <dataspace/capability.h>
|
||||||
#include <audio_out_session/capability.h>
|
#include <base/rpc.h>
|
||||||
#include <packet_stream_tx/packet_stream_tx.h>
|
|
||||||
#include <session/session.h>
|
#include <session/session.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Audio_out {
|
namespace Audio_out {
|
||||||
|
class Packet;
|
||||||
|
class Stream;
|
||||||
|
class Session;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
QUEUE_SIZE = 16, /* buffer queue size */
|
QUEUE_SIZE = 16, /* buffer queue size */
|
||||||
FRAME_SIZE = 4, /* frame size in bytes */
|
PERIOD = 2048, /* samples per period */
|
||||||
PERIOD = 1024 /* frames per period */
|
SAMPLE_RATE = 44100,
|
||||||
};
|
SAMPLE_SIZE = sizeof(float),
|
||||||
|
|
||||||
struct Session : Genode::Session
|
|
||||||
{
|
|
||||||
typedef Packet_stream_policy<Packet_descriptor,
|
|
||||||
QUEUE_SIZE, QUEUE_SIZE,
|
|
||||||
float> Policy;
|
|
||||||
|
|
||||||
typedef Packet_stream_tx::Channel<Policy> 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>, channel_cap);
|
|
||||||
|
|
||||||
GENODE_RPC_INTERFACE(Rpc_flush, Rpc_sync_session, Rpc_channel_cap);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_ */
|
#endif /* _INCLUDE__AUDIO_OUT_SESSION__AUDIO_OUT_SESSION_H_ */
|
||||||
|
@ -25,6 +25,7 @@ namespace Audio_out {
|
|||||||
* because this file relies on the 'Audio_out::Session_capability' type.
|
* because this file relies on the 'Audio_out::Session_capability' type.
|
||||||
*/
|
*/
|
||||||
class Session;
|
class Session;
|
||||||
typedef Genode::Capability<Session> Session_capability; }
|
typedef Genode::Capability<Session> Session_capability;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__AUDIO_OUT_SESSION__CAPABILITY_H_ */
|
#endif /* _INCLUDE__AUDIO_OUT_SESSION__CAPABILITY_H_ */
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Client-side audio-out session interface
|
* \brief Client-side Audio_out-session
|
||||||
* \author Norman Feske
|
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
* \author Christian Helmuth
|
* \date 2012-12-20
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2009-12-02
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -17,58 +14,138 @@
|
|||||||
#ifndef _INCLUDE__AUDIO_OUT_SESSION__CLIENT_H_
|
#ifndef _INCLUDE__AUDIO_OUT_SESSION__CLIENT_H_
|
||||||
#define _INCLUDE__AUDIO_OUT_SESSION__CLIENT_H_
|
#define _INCLUDE__AUDIO_OUT_SESSION__CLIENT_H_
|
||||||
|
|
||||||
|
#include <base/env.h>
|
||||||
#include <base/rpc_client.h>
|
#include <base/rpc_client.h>
|
||||||
#include <audio_out_session/audio_out_session.h>
|
#include <audio_out_session/audio_out_session.h>
|
||||||
#include <packet_stream_tx/client.h>
|
|
||||||
|
|
||||||
namespace Audio_out {
|
namespace Audio_out {
|
||||||
|
struct Signal;
|
||||||
|
struct Session_client;
|
||||||
|
}
|
||||||
|
|
||||||
class Session_client : public Genode::Rpc_client<Session>
|
|
||||||
|
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<Session>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Packet_stream_tx::Client<Session::Channel> _channel;
|
Signal _progress;
|
||||||
|
Signal _alloc;
|
||||||
|
|
||||||
Session_capability _cap;
|
Genode::Signal_transmitter _data_avail;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* \param session Audio-out session capability
|
* \param session session capability
|
||||||
* \param buffer_alloc allocator used for managing the
|
* \param alloc_signal true, install 'alloc_signal' receiver
|
||||||
* transmission buffer
|
* \param progress_signal true, install 'progress_signal' receiver
|
||||||
*/
|
*/
|
||||||
Session_client(Genode::Capability<Session> session,
|
Session_client(Genode::Capability<Session> session, bool alloc_signal,
|
||||||
Genode::Range_allocator *buffer_alloc)
|
bool progress_signal)
|
||||||
:
|
:
|
||||||
Genode::Rpc_client<Session>(session),
|
Genode::Rpc_client<Session>(session),
|
||||||
_channel(call<Rpc_channel_cap>(), buffer_alloc),
|
_data_avail(call<Rpc_data_avail_sigh>())
|
||||||
_cap(session)
|
{
|
||||||
{ }
|
/* ask server for stream data space and attach it */
|
||||||
|
_stream = static_cast<Stream *>(Genode::env()->rm_session()->attach(call<Rpc_dataspace>()));
|
||||||
|
|
||||||
/**
|
if (progress_signal)
|
||||||
* Return session capability of this session
|
progress_sigh(_progress.cap);
|
||||||
*
|
|
||||||
* 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; }
|
if (alloc_signal)
|
||||||
|
alloc_sigh(_alloc.cap);
|
||||||
/*********************************
|
|
||||||
** Audio-out session interface **
|
|
||||||
*********************************/
|
|
||||||
|
|
||||||
Session::Channel::Source *stream() { return _channel.source(); }
|
|
||||||
|
|
||||||
void flush(void) { call<Rpc_flush>(); }
|
|
||||||
|
|
||||||
void sync_session(Session_capability audio_out_session) {
|
|
||||||
call<Rpc_sync_session>(audio_out_session); }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************
|
||||||
|
** Signals **
|
||||||
|
*************/
|
||||||
|
|
||||||
|
void progress_sigh(Genode::Signal_context_capability sigh) {
|
||||||
|
call<Rpc_progress_sigh>(sigh); }
|
||||||
|
|
||||||
|
void alloc_sigh(Genode::Signal_context_capability sigh) {
|
||||||
|
call<Rpc_alloc_sigh>(sigh); }
|
||||||
|
|
||||||
|
Genode::Signal_context_capability data_avail_sigh() {
|
||||||
|
return Genode::Signal_context_capability(); }
|
||||||
|
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
** Session interface **
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
call<Rpc_start>();
|
||||||
|
|
||||||
|
/* reset tail pointer */
|
||||||
|
stream()->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() { call<Rpc_stop>(); }
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
** 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_ */
|
#endif /* _INCLUDE__AUDIO_OUT_SESSION__CLIENT_H_ */
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Connection to audio-out service
|
* \brief Connection to audio service
|
||||||
* \author Norman Feske
|
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
* \author Christian Helmuth
|
* \date 2012-12-20
|
||||||
* \date 2009-12-01
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -20,30 +18,33 @@
|
|||||||
#include <base/connection.h>
|
#include <base/connection.h>
|
||||||
#include <base/allocator.h>
|
#include <base/allocator.h>
|
||||||
|
|
||||||
namespace Audio_out {
|
|
||||||
|
|
||||||
struct Connection : Genode::Connection<Session>, Session_client
|
namespace Audio_out {
|
||||||
|
struct Connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Audio_out::Connection : Genode::Connection<Session>, Audio_out::Session_client
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* \param channel channel identifier (e.g., "front left")
|
* \param channel channel identifier (e.g., "front left")
|
||||||
* \param buffer_alloc allocator used for managing the
|
* \param alloc_signal install 'alloc_signal', the client may then use
|
||||||
* transmission buffer
|
* 'wait_for_alloc' when the stream is full
|
||||||
* \param buffer_size size of transmission buffer in bytes
|
* \param progress_signal install progress signal, the client may then
|
||||||
* (defaults to all packets of the queue plus
|
* call 'wait_for_progress', which is sent when the
|
||||||
* some space for metadata)
|
* server processed one or more packets
|
||||||
*/
|
*/
|
||||||
Connection(const char *channel,
|
Connection(const char *channel,
|
||||||
Genode::Range_allocator *buffer_alloc,
|
bool alloc_signal = true,
|
||||||
Genode::size_t buffer_size = QUEUE_SIZE * FRAME_SIZE * PERIOD + 0x400)
|
bool progress_signal = false)
|
||||||
:
|
:
|
||||||
Genode::Connection<Session>(
|
Genode::Connection<Session>(
|
||||||
session("ram_quota=%zd, channel=\"%s\", buffer_size=%zd",
|
session("ram_quota=%zd, channel=\"%s\"",
|
||||||
3*4096 + buffer_size, channel, buffer_size)),
|
2*4096 + sizeof(Stream), channel)),
|
||||||
Session_client(cap(), buffer_alloc)
|
Session_client(cap(), alloc_signal, progress_signal)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__AUDIO_OUT_SESSION__CONNECTION_H_ */
|
#endif /* _INCLUDE__AUDIO_OUT_SESSION__CONNECTION_H_ */
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Server-side audio-out session interface
|
* \brief Server-side audio-session interface
|
||||||
* \author Norman Feske
|
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
* \author Christian Helmuth
|
* \date 2012-12-10
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2009-12-02
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -17,41 +14,112 @@
|
|||||||
#ifndef _INCLUDE__AUDIO_OUT_SESSION__RPC_OBJECT_H_
|
#ifndef _INCLUDE__AUDIO_OUT_SESSION__RPC_OBJECT_H_
|
||||||
#define _INCLUDE__AUDIO_OUT_SESSION__RPC_OBJECT_H_
|
#define _INCLUDE__AUDIO_OUT_SESSION__RPC_OBJECT_H_
|
||||||
|
|
||||||
|
#include <base/env.h>
|
||||||
#include <base/rpc_server.h>
|
#include <base/rpc_server.h>
|
||||||
#include <audio_out_session/audio_out_session.h>
|
#include <audio_out_session/audio_out_session.h>
|
||||||
#include <packet_stream_tx/rpc_object.h>
|
|
||||||
|
|
||||||
namespace Audio_out {
|
namespace Audio_out {
|
||||||
|
class Session_rpc_object;
|
||||||
|
}
|
||||||
|
|
||||||
class Session_rpc_object : public Genode::Rpc_object<Session, Session_rpc_object>
|
|
||||||
|
class Audio_out::Session_rpc_object : public Genode::Rpc_object<Audio_out::Session,
|
||||||
|
Session_rpc_object>
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Packet_stream_tx::Rpc_object<Channel> _channel;
|
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:
|
public:
|
||||||
|
|
||||||
/**
|
Session_rpc_object(Genode::Signal_context_capability data_cap)
|
||||||
* Constructor
|
:
|
||||||
*
|
_stopped(true), _data_cap(data_cap),
|
||||||
* \param ds dataspace used as communication buffer
|
_progress_sigh(false), _alloc_sigh(false)
|
||||||
* for the packet stream
|
{
|
||||||
* \param ep entry point used for packet-stream channel
|
_ds = Genode::env()->ram_session()->alloc(sizeof(Stream));
|
||||||
*/
|
_stream = static_cast<Stream *>(Genode::env()->rm_session()->attach(_ds));
|
||||||
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> channel_cap() { return _channel.cap(); }
|
|
||||||
|
|
||||||
Channel::Sink *channel() { return _channel.sink(); }
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_ */
|
#endif /* _INCLUDE__AUDIO_OUT_SESSION__RPC_OBJECT_H_ */
|
||||||
|
@ -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 <base/allocator.h>
|
|
||||||
#include <dataspace/capability.h>
|
|
||||||
#include <base/rpc.h>
|
|
||||||
#include <session/session.h>
|
|
||||||
|
|
||||||
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_ */
|
|
@ -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 <base/env.h>
|
|
||||||
#include <base/rpc_client.h>
|
|
||||||
#include <audio_session/audio_session.h>
|
|
||||||
|
|
||||||
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<Session>
|
|
||||||
{
|
|
||||||
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> session, bool alloc_signal, bool progress_signal)
|
|
||||||
:
|
|
||||||
Genode::Rpc_client<Session>(session),
|
|
||||||
_data_avail(call<Rpc_data_avail_sigh>())
|
|
||||||
{
|
|
||||||
/* ask server for stream data space and attach it */
|
|
||||||
_stream = static_cast<Stream *>(Genode::env()->rm_session()->attach(call<Rpc_dataspace>()));
|
|
||||||
|
|
||||||
if (progress_signal)
|
|
||||||
progress_sigh(_progress.cap);
|
|
||||||
|
|
||||||
if (alloc_signal)
|
|
||||||
alloc_sigh(_alloc.cap);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*************
|
|
||||||
** Signals **
|
|
||||||
*************/
|
|
||||||
|
|
||||||
void progress_sigh(Genode::Signal_context_capability sigh) { call<Rpc_progress_sigh>(sigh); }
|
|
||||||
void alloc_sigh(Genode::Signal_context_capability sigh) { call<Rpc_alloc_sigh>(sigh); }
|
|
||||||
|
|
||||||
Genode::Signal_context_capability data_avail_sigh() {
|
|
||||||
return Genode::Signal_context_capability(); }
|
|
||||||
|
|
||||||
|
|
||||||
/***********************
|
|
||||||
** Session interface **
|
|
||||||
***********************/
|
|
||||||
|
|
||||||
void start()
|
|
||||||
{
|
|
||||||
call<Rpc_start>();
|
|
||||||
|
|
||||||
/* reset tail pointer */
|
|
||||||
stream()->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop() { call<Rpc_stop>(); }
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************
|
|
||||||
** 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_ */
|
|
@ -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 <audio_session/client.h>
|
|
||||||
#include <base/connection.h>
|
|
||||||
#include <base/allocator.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Audio_out {
|
|
||||||
struct Connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct Audio_out::Connection : Genode::Connection<Session>, 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>(
|
|
||||||
session("ram_quota=%zd, channel=\"%s\"",
|
|
||||||
2*4096 + sizeof(Stream), channel)),
|
|
||||||
Session_client(cap(), alloc_signal, progress_signal)
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__AUDIO_SESSION__CONNECTION_H_ */
|
|
@ -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 <base/env.h>
|
|
||||||
#include <base/rpc_server.h>
|
|
||||||
#include <audio_session/audio_session.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace Audio_out {
|
|
||||||
class Session_rpc_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Audio_out::Session_rpc_object : public Genode::Rpc_object<Audio_out::Session,
|
|
||||||
Session_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<Stream *>(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_ */
|
|
@ -20,7 +20,7 @@
|
|||||||
#include <base/sleep.h>
|
#include <base/sleep.h>
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#include <audio_session/rpc_object.h>
|
#include <audio_out_session/rpc_object.h>
|
||||||
#include <util/misc_math.h>
|
#include <util/misc_math.h>
|
||||||
|
|
||||||
#include "alsa.h"
|
#include "alsa.h"
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/sleep.h>
|
#include <base/sleep.h>
|
||||||
|
|
||||||
#include <audio_session/rpc_object.h>
|
#include <audio_out_session/rpc_object.h>
|
||||||
#include <audio_session/connection.h>
|
#include <audio_out_session/connection.h>
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
#include <timer_session/connection.h>
|
#include <timer_session/connection.h>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <audio_session/connection.h>
|
#include <audio_out_session/connection.h>
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
#include <base/sleep.h>
|
#include <base/sleep.h>
|
||||||
#include <rom_session/connection.h>
|
#include <rom_session/connection.h>
|
||||||
|
Reference in New Issue
Block a user