diff --git a/repos/os/src/drivers/audio/spec/linux/alsa.c b/repos/os/src/drivers/audio/spec/linux/alsa.c
index a07aa5b6b6..4b92a64059 100644
--- a/repos/os/src/drivers/audio/spec/linux/alsa.c
+++ b/repos/os/src/drivers/audio/spec/linux/alsa.c
@@ -63,9 +63,6 @@ int audio_drv_init(char const * const device)
}
-void audio_drv_adopt_myself() { }
-
-
int audio_drv_play(void *data, int frame_cnt)
{
int err;
diff --git a/repos/os/src/drivers/audio/spec/linux/alsa.h b/repos/os/src/drivers/audio/spec/linux/alsa.h
index 11c2fd1d50..d4b472b349 100644
--- a/repos/os/src/drivers/audio/spec/linux/alsa.h
+++ b/repos/os/src/drivers/audio/spec/linux/alsa.h
@@ -20,7 +20,6 @@ extern "C" {
#endif
int audio_drv_init(char const * const);
-void audio_drv_adopt_myself();
int audio_drv_play(void *data, int frame_cnt);
void audio_drv_stop(void);
void audio_drv_start(void);
diff --git a/repos/os/src/drivers/audio/spec/linux/main.cc b/repos/os/src/drivers/audio/spec/linux/main.cc
index 1089d4bb29..58c406f256 100644
--- a/repos/os/src/drivers/audio/spec/linux/main.cc
+++ b/repos/os/src/drivers/audio/spec/linux/main.cc
@@ -2,20 +2,20 @@
* \brief Audio_out-out driver for Linux
* \author Christian Helmuth
* \author Sebastian Sumpf
+ * \author Josef Soentgen
* \date 2010-05-11
*
* FIXME session and driver shutdown not implemented (audio_drv_stop)
- *
- * 2013-01-09: Adapted to news audio interface
*/
/*
- * Copyright (C) 2010-2013 Genode Labs GmbH
+ * Copyright (C) 2010-2016 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.
*/
+/* Genode includes */
#include
#include
#include
@@ -23,7 +23,10 @@
#include
#include
#include
+#include
+#include
+/* local includes */
#include "alsa.h"
using namespace Genode;
@@ -88,16 +91,19 @@ static bool channel_number_from_string(const char *name,
}
-
/*
* Root component, handling new session requests.
*/
-class Audio_out::Out : public Thread<1024 * sizeof(addr_t)>
+class Audio_out::Out
{
private:
- Signal_receiver *_data_recv; /* data is available */
-
+ Server::Entrypoint &_ep;
+ Genode::Signal_rpc_member _data_avail_dispatcher;
+ Genode::Signal_rpc_member _timer_dispatcher;
+
+ Timer::Connection _timer;
+
bool _active() {
return channel_acquired[LEFT] && channel_acquired[RIGHT] &&
channel_acquired[LEFT]->active() && channel_acquired[RIGHT]->active();
@@ -135,63 +141,60 @@ class Audio_out::Out : public Thread<1024 * sizeof(addr_t)>
Packet *p_left = left()->get(left()->pos());
Packet *p_right = right()->get(left()->pos());
- bool found = false;
- for (int i = 0; i < QUEUE_SIZE; i++) {
- if (p_left->valid() && p_right->valid()) {
- found = true;
- break;
- }
-
- p_left = left()->next(p_left);
- p_right = right()->next(p_right);
- }
-
- if (!found)
- return false;
-
/* convert float to S16LE */
static short data[2 * PERIOD];
- for (int i = 0; i < 2 * PERIOD; i += 2) {
- data[i] = p_left->content()[i / 2] * 32767;
- data[i + 1] = p_right->content()[i / 2] * 32767;
- }
+ if (p_left->valid() && p_right->valid()) {
- p_left->invalidate();
- p_right->invalidate();
-
- if (verbose)
- PDBG("play packet");
-
- /* blocking-write packet to ALSA */
- while (int err = audio_drv_play(data, PERIOD)) {
- if (verbose) PERR("Error %d during playback", err);
- audio_drv_stop();
- audio_drv_start();
+ for (int i = 0; i < 2 * PERIOD; i += 2) {
+ data[i] = p_left->content()[i / 2] * 32767;
+ data[i + 1] = p_right->content()[i / 2] * 32767;
}
- p_left->mark_as_played();
- p_right->mark_as_played();
+ p_left->invalidate();
+ p_right->invalidate();
+
+ if (verbose)
+ PDBG("play packet");
+
+ /* blocking-write packet to ALSA */
+ while (int err = audio_drv_play(data, PERIOD)) {
+ if (verbose) PERR("Error %d during playback", err);
+ audio_drv_stop();
+ audio_drv_start();
+ }
+
+ p_left->mark_as_played();
+ p_right->mark_as_played();
+ }
_advance_position(p_left, p_right);
return true;
}
+ void _handle_data_avail(unsigned num) { }
+
+ void _handle_timer(unsigned)
+ {
+ if (_active()) _play_packet();
+ }
+
public:
- Out(Signal_receiver *data_recv)
- : Thread("audio_out"), _data_recv(data_recv) { }
-
- void entry()
+ Out(Server::Entrypoint &ep)
+ :
+ _ep(ep),
+ _data_avail_dispatcher(ep, *this, &Audio_out::Out::_handle_data_avail),
+ _timer_dispatcher(ep, *this, &Audio_out::Out::_handle_timer)
{
- audio_drv_adopt_myself();
+ _timer.sigh(_timer_dispatcher);
- /* handle audio out */
- while (true)
- if (!_active() || !_play_packet())
- _data_recv->wait_for_signal();
+ unsigned const us = (Audio_out::PERIOD * 1000 / Audio_out::SAMPLE_RATE)*1000;
+ _timer.trigger_periodic(us);
}
+
+ Signal_context_capability data_avail_sigh() { return _data_avail_dispatcher; }
};
@@ -257,47 +260,50 @@ class Audio_out::Root : public Audio_out::Root_component
public:
- Root(Rpc_entrypoint *session_ep, Allocator *md_alloc, Signal_context_capability data_cap)
- : Root_component(session_ep, md_alloc), _data_cap(data_cap)
+ Root(Server::Entrypoint &ep, Allocator *md_alloc,
+ Signal_context_capability data_cap)
+ : Root_component(&ep.rpc_ep(), md_alloc), _data_cap(data_cap)
{ }
};
-int main(int argc, char **argv)
+struct Main
{
- /* setup data available signal */
- static Signal_receiver data_recv;
- static Signal_context data_context;
- static Signal_context_capability data_cap(data_recv.manage(&data_context));
+ Server::Entrypoint &ep;
- char dev[32] = { 'h', 'w', 0 };
- try {
- Genode::Xml_node config = Genode::config()->xml_node();
- config.attribute("alsa_device").value(dev, sizeof(dev));
- } catch (...) { }
+ Main(Server::Entrypoint &ep) : ep(ep)
+ {
+ char dev[32] = { 'h', 'w', 0 };
+ try {
+ Genode::Xml_node config = Genode::config()->xml_node();
+ config.attribute("alsa_device").value(dev, sizeof(dev));
+ } catch (...) { }
- /* init ALSA */
- int err = audio_drv_init(dev);
- if (err) {
- if (err == -1) PERR("Could not open ALSA device '%s'.", dev);
- else PERR("audio driver init returned %d", err);
- return 0;
+ /* init ALSA */
+ int err = audio_drv_init(dev);
+ if (err) {
+ if (err == -1) PERR("Could not open ALSA device '%s'.", dev);
+ else PERR("Could not initialize driver, error: %d", err);
+
+ throw -1;
+ }
+ audio_drv_start();
+
+ static Audio_out::Out out(ep);
+ static Audio_out::Root root(ep, Genode::env()->heap(),
+ out.data_avail_sigh());
+ env()->parent()->announce(ep.manage(root));
+ PINF("--- start Audio_out ALSA driver ---");
}
- audio_drv_start();
+};
- /* start output thread */
- Audio_out::Out *out = new(env()->heap()) Audio_out::Out(&data_recv);
- out->start();
- enum { STACK_SIZE = 1024 * sizeof(addr_t) };
- static Cap_connection cap;
- static Rpc_entrypoint ep(&cap, STACK_SIZE, "audio_ep");
+/************
+ ** Server **
+ ************/
- /* setup service */
- static Audio_out::Root audio_root(&ep, env()->heap(), data_cap);
- env()->parent()->announce(ep.manage(&audio_root));
-
- sleep_forever();
- return 0;
+namespace Server {
+ char const *name() { return "audio_drv_ep"; }
+ size_t stack_size() { return 2*1024*sizeof(addr_t); }
+ void construct(Entrypoint &ep) { static Main main(ep); }
}
-
diff --git a/repos/os/src/drivers/audio/spec/linux/target.mk b/repos/os/src/drivers/audio/spec/linux/target.mk
index f2e31531dd..3eec36b163 100644
--- a/repos/os/src/drivers/audio/spec/linux/target.mk
+++ b/repos/os/src/drivers/audio/spec/linux/target.mk
@@ -1,6 +1,6 @@
REQUIRES = linux
TARGET = audio_drv
-LIBS = lx_hybrid config
+LIBS = lx_hybrid config server
SRC_CC = main.cc
SRC_C = alsa.c
LX_LIBS = alsa