diff --git a/dde_oss/src/drivers/oss/include/audio.h b/dde_oss/src/drivers/oss/include/audio.h
index 0174aeb89f..0cf11aec3a 100644
--- a/dde_oss/src/drivers/oss/include/audio.h
+++ b/dde_oss/src/drivers/oss/include/audio.h
@@ -22,6 +22,6 @@ int audio_init();
/**
* Play data of size
*/
-int audio_play(short *data, int size);
+int audio_play(short *data, unsigned size);
#endif /* _INCLUDE__AUDIO_H_ */
diff --git a/dde_oss/src/drivers/oss/include/os.h b/dde_oss/src/drivers/oss/include/os.h
index 2653baa87b..f98ecee32c 100644
--- a/dde_oss/src/drivers/oss/include/os.h
+++ b/dde_oss/src/drivers/oss/include/os.h
@@ -196,7 +196,7 @@ enum {
#define GET_PROCESS_PID(p) -1
#define KERNEL_MALLOC(size) (dde_kit_large_malloc(size))
-#define KERNEL_FREE(ptr) (dde_kit_large_free(ptr))
+#define KERNEL_FREE(ptr) (dde_kit_large_free(ptr))
void * dma_alloc(oss_native_word *phys, size_t size);
#define CONTIG_MALLOC(osdev, sz, memlimit, phaddr, handle) dma_alloc(phaddr, sz)
diff --git a/dde_oss/src/drivers/oss/main.cc b/dde_oss/src/drivers/oss/main.cc
index 6cbe34a9ad..f0d624467d 100644
--- a/dde_oss/src/drivers/oss/main.cc
+++ b/dde_oss/src/drivers/oss/main.cc
@@ -1,5 +1,5 @@
/*
- * \brief Audio-session-entry point
+ * \brief Audio-out session entry point
* \author Sebastian Sumpf
* \date 2012-11-20
*/
@@ -19,7 +19,7 @@ extern "C" {
#include
#include
#include
-#include
+#include
#include
#include
@@ -27,202 +27,253 @@ extern "C" {
using namespace Genode;
+
static const bool verbose = false;
static bool audio_out_active = false;
+enum Channel_number { LEFT, RIGHT, MAX_CHANNELS, INVALID = MAX_CHANNELS };
+
namespace Audio_out {
-
- class Session_component;
-
- enum Channel_number { LEFT, RIGHT, MAX_CHANNELS, INVALID = MAX_CHANNELS };
-
+ class Session_component;
+ class Out;
+ class Root;
+ struct Root_policy;
static Session_component *channel_acquired[MAX_CHANNELS];
+}
- class Session_component : public Session_rpc_object
- {
- private:
- Ram_dataspace_capability _ds;
- Channel_number _channel;
+class Audio_out::Session_component : public Audio_out::Session_rpc_object
+{
+ private:
- Signal_dispatcher _process_packet_dispatcher;
+ Channel_number _channel;
+ Signal_context_capability _ctx_cap;
+ Signal_transmitter _signal;
- Ram_dataspace_capability _alloc_dataspace(size_t size)
- {
- _ds = env()->ram_session()->alloc(size);
- return _ds;
- }
+ public:
- void _process_packets(unsigned)
- {
- /* handle audio-out packets */
- Session_component *left = channel_acquired[LEFT],
- *right = channel_acquired[RIGHT];
- while (left->channel()->packet_avail() &&
- right->channel()->packet_avail() &&
- left->channel()->ready_to_ack() &&
- right->channel()->ready_to_ack()) {
+ Session_component(Channel_number channel, Signal_context_capability ctx_cap)
+ : Session_rpc_object(ctx_cap), _channel(channel), _ctx_cap(ctx_cap)
+ {
+ Audio_out::channel_acquired[_channel] = this;
+ _signal.context(ctx_cap);
+ }
- /* get packets for channels */
- Packet_descriptor p[MAX_CHANNELS];
- static short data[2 * PERIOD];
- p[LEFT] = left->channel()->get_packet();
- p[RIGHT] = right->channel()->get_packet();
+ ~Session_component()
+ {
+ Audio_out::channel_acquired[_channel] = 0;
+ }
- /* convert float to S16LE */
- for (int i = 0; i < 2 * PERIOD; i += 2) {
- data[i] = left->channel()->packet_content(p[LEFT])[i / 2] * 32767;
- data[i + 1] = right->channel()->packet_content(p[RIGHT])[i / 2] * 32767;
- }
+ void start()
+ {
+ Session_rpc_object::start();
+ /* this will trigger Audio_out::Out::handle */
+ _signal.submit();
+ }
+};
- if (verbose)
- PDBG("play packet");
- /* send to driver */
- int err;
- if (audio_out_active)
- if ((err = audio_play(data, 4 * PERIOD)))
- PWRN("Error %d during playback", err);
+class Audio_out::Out : public Driver_context
+{
+ private:
- /* acknowledge packet to the client */
- if (p[LEFT].valid())
- left->channel()->acknowledge_packet(p[LEFT]);
+ bool _active() {
+ return channel_acquired[LEFT] && channel_acquired[RIGHT] &&
+ channel_acquired[LEFT]->active() && channel_acquired[RIGHT]->active();
+ }
- if (p[RIGHT].valid())
- right->channel()->acknowledge_packet(p[RIGHT]);
+ Stream *left() { return channel_acquired[LEFT]->stream(); }
+ Stream *right() { return channel_acquired[RIGHT]->stream(); }
+
+ void _advance_position(Packet *l, Packet *r)
+ {
+ bool full_left = left()->full();
+ bool full_right = right()->full();
+
+ left()->pos(left()->packet_position(l));
+ right()->pos(right()->packet_position(r));
+
+ left()->increment_position();
+ right()->increment_position();
+
+ Session_component *channel_left = channel_acquired[LEFT];
+ Session_component *channel_right = channel_acquired[RIGHT];
+
+ if (full_left)
+ channel_left->alloc_submit();
+
+ if (full_right)
+ channel_right->alloc_submit();
+
+ channel_left->progress_submit();
+ channel_right->progress_submit();
+ }
+
+ bool _play_packet()
+ {
+ Packet *p_left = left()->get(left()->pos());
+ Packet *p_right = right()->get(right()->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);
}
- public:
+ if (!found)
+ return false;
- Session_component(Channel_number channel, size_t buffer_size,
- Rpc_entrypoint &ep, Signal_receiver &sig_rec)
- : Session_rpc_object(_alloc_dataspace(buffer_size), ep), _channel(channel),
- _process_packet_dispatcher(sig_rec, *this,
- &Session_component::_process_packets)
- {
- Audio_out::channel_acquired[_channel] = this;
- Session_rpc_object::_channel.sigh_packet_avail(_process_packet_dispatcher);
- Session_rpc_object::_channel.sigh_ready_to_ack(_process_packet_dispatcher);
+ /* 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;
}
- ~Session_component()
- {
- Audio_out::channel_acquired[_channel] = 0;
+ p_left->invalidate();
+ p_right->invalidate();
- env()->ram_session()->free(_ds);
+ if (verbose)
+ PDBG("play packet");
+
+ /* send to driver */
+ int err;
+ if (audio_out_active)
+ if ((err = audio_play(data, 4 * PERIOD)))
+ PWRN("Error %d during playback", err);
+
+ p_left->mark_as_played();
+ p_right->mark_as_played();
+
+ _advance_position(p_left, p_right);
+
+ return true;
+ }
+
+
+ public:
+
+ void handle()
+ {
+ while (true) {
+ if (!_active()) {
+ //TODO: may stop device
+ return;
+ }
+
+ /* play one packet */
+ if (!_play_packet())
+ return;
+
+ /* give others a try */
+ Service_handler::s()->check_signal(false);
}
+ }
- /*********************************
- ** Audio-out-session interface **
- *********************************/
+ const char *debug() { return "Audio out"; }
+};
- void flush()
- {
- while (channel()->packet_avail())
- channel()->acknowledge_packet(channel()->get_packet());
- }
- void sync_session(Session_capability audio_out_session) { }
+static bool channel_number_from_string(const char *name,
+ Channel_number *out_number)
+{
+ static struct Names {
+ const char *name;
+ Channel_number number;
+ } names[] = {
+ { "left", LEFT }, { "front left", LEFT },
+ { "right", RIGHT }, { "front right", RIGHT },
+ { 0, INVALID }
};
- static bool channel_number_from_string(const char *name,
- Channel_number *out_number)
+ for (Names *n = names; n->name; ++n)
+ if (!Genode::strcmp(name, n->name)) {
+ *out_number = n->number;
+ return true;
+ }
+
+ return false;
+}
+
+
+/**
+ * Session creation policy for our service
+ */
+struct Audio_out::Root_policy
+{
+ void aquire(const char *args)
{
- static struct Names {
- const char *name;
- Channel_number number;
- } names[] = {
- { "left", LEFT }, { "front left", LEFT },
- { "right", RIGHT }, { "front right", RIGHT },
- { 0, INVALID }
- };
+ size_t ram_quota =
+ Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
+ size_t session_size =
+ align_addr(sizeof(Audio_out::Session_component), 12);
- for (Names *n = names; n->name; ++n)
- if (!Genode::strcmp(name, n->name)) {
- *out_number = n->number;
- return true;
- }
+ if ((ram_quota < session_size) ||
+ (sizeof(Stream) > ram_quota - session_size)) {
+ PERR("insufficient 'ram_quota', got %zd, need %zd",
+ ram_quota, sizeof(Stream) + session_size);
+ throw ::Root::Quota_exceeded();
+ }
- return false;
+ char channel_name[16];
+ Channel_number channel_number;
+ Arg_string::find_arg(args, "channel").string(channel_name,
+ sizeof(channel_name),
+ "left");
+ if (!channel_number_from_string(channel_name, &channel_number))
+ throw ::Root::Invalid_args();
+ if (Audio_out::channel_acquired[channel_number])
+ throw ::Root::Unavailable();
}
- /**
- * Session creation policy for our service
- */
- struct Root_policy
- {
- void aquire(const char *args)
- {
- size_t ram_quota =
- Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
- size_t buffer_size =
- Arg_string::find_arg(args, "buffer_size").ulong_value(0);
- size_t session_size =
- align_addr(sizeof(Session_component), 12);
+ void release() { }
+};
- if ((ram_quota < session_size) ||
- (buffer_size > ram_quota - session_size)) {
- PERR("insufficient 'ram_quota', got %zd, need %zd",
- ram_quota, buffer_size + session_size);
- throw Root::Quota_exceeded();
- }
+
+namespace Audio_out {
+ typedef Root_component Root_component;
+}
+
+
+/**
+ * Root component, handling new session requests.
+ */
+class Audio_out::Root : public Audio_out::Root_component
+{
+ private:
+
+ Signal_context_capability _ctx_cap;
+
+ protected:
+
+ Session_component *_create_session(const char *args)
+ {
+ if (!audio_out_active)
+ throw Root::Unavailable();
char channel_name[16];
- Channel_number channel_number;
+ Channel_number channel_number = INVALID;
Arg_string::find_arg(args, "channel").string(channel_name,
sizeof(channel_name),
"left");
- if (!channel_number_from_string(channel_name, &channel_number))
- throw Root::Invalid_args();
- if (channel_acquired[channel_number])
- throw Root::Unavailable();
+ channel_number_from_string(channel_name, &channel_number);
+
+ return new (md_alloc())
+ Session_component(channel_number, _ctx_cap);
}
- void release() { }
- };
+ public:
- typedef Root_component Root_component;
-
- /*
- * Root component, handling new session requests.
- */
- class Root : public Root_component
- {
- private:
-
- Rpc_entrypoint &_channel_ep;
- Signal_receiver &_sig_rec;
-
- protected:
-
- Session_component *_create_session(const char *args)
- {
- size_t buffer_size =
- Arg_string::find_arg(args, "buffer_size").ulong_value(0);
-
- if (!audio_out_active)
- throw Root::Unavailable();
-
- char channel_name[16];
- Channel_number channel_number = INVALID;
- Arg_string::find_arg(args, "channel").string(channel_name,
- sizeof(channel_name),
- "left");
- channel_number_from_string(channel_name, &channel_number);
-
- return new (md_alloc())
- Session_component(channel_number, buffer_size, _channel_ep, _sig_rec);
- }
-
- public:
-
- Root(Rpc_entrypoint &session_ep, Allocator *md_alloc, Signal_receiver &sig_rec)
- : Root_component(&session_ep, md_alloc), _channel_ep(session_ep), _sig_rec(sig_rec)
- { }
- };
-}
+ Root(Rpc_entrypoint *session_ep, Allocator *md_alloc, Signal_context_capability ctx_cap)
+ : Root_component(session_ep, md_alloc), _ctx_cap(ctx_cap)
+ { }
+};
int main()
@@ -242,7 +293,8 @@ int main()
audio_out_active = audio_init() ? false : true;
if (audio_out_active) {
- static Audio_out::Root audio_root(ep, env()->heap(), recv);
+ static Audio_out::Out out;
+ static Audio_out::Root audio_root(&ep, env()->heap(), recv.manage(&out));
env()->parent()->announce(ep.manage(&audio_root));
}
diff --git a/dde_oss/src/drivers/oss/os.cc b/dde_oss/src/drivers/oss/os.cc
index ce6b73d051..4c2fe2eb98 100644
--- a/dde_oss/src/drivers/oss/os.cc
+++ b/dde_oss/src/drivers/oss/os.cc
@@ -350,7 +350,7 @@ int audio_init()
}
/* set fragment policy (TODO: make configurable) */
- int policy = 8;
+ int policy = 1;
if (ioctl_dsp(SNDCTL_DSP_POLICY, &policy) == -1)
PERR("Error setting policy");
@@ -379,12 +379,12 @@ int audio_init()
}
-int audio_play(short *data, int size)
+int audio_play(short *data, unsigned size)
{
uio_t io = { (char *)data, size, UIO_WRITE };
int ret;
- if ((ret = dsp_drv->write(0, 0, &io, size)) != size)
+ if ((ret = dsp_drv->write(0, 0, &io, size)) != (int)size)
PERR("Error writing data s: %d r: %d func %p", size, ret, dsp_drv->write);
Irq::check_irq();
diff --git a/libports/run/avplay.run b/libports/run/avplay.run
index 923f52564a..92f1370485 100644
--- a/libports/run/avplay.run
+++ b/libports/run/avplay.run
@@ -1,10 +1,29 @@
+#
+# Build
+#
+
build {
core init
drivers/timer
- drivers/framebuffer drivers/pci drivers/input drivers/audio_out
- app/avplay
+ drivers/framebuffer drivers/pci drivers/input drivers/oss
+ server/mixer
+ app/avplay drivers/acpi
}
+#
+# Download media file
+#
+
+set media_url "ftp://ftp.untergrund.net/users/ae/dhstv/escape-chotro.mp4"
+if {![file exists bin/mediafile]} {
+ puts "downloading media file from $media_url"
+ catch { exec wget -O bin/mediafile $media_url }
+}
+
+#
+# Generate config
+#
+
create_boot_directory
set config {
@@ -36,11 +55,28 @@ append_if [have_spec sdl] config {
}
-append_if [have_spec pci] config {
+append_if [have_spec acpi] config {
+
+
+
+
+
+
+
+
+
+
+
+}
+
+append_if [expr [have_spec pci] && ![have_spec acpi]] config {
-
-
- }
+
+
+
+
+
+}
append_if [have_spec vesa] config {
@@ -59,10 +95,23 @@ append config {
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -70,14 +119,23 @@ append config {
+
+
+
+
+
}
install_config $config
+#
+# Boot modules
+#
+
set boot_modules {
- core init timer audio_out_drv avplay
+ core init timer oss_drv mixer avplay
ld.lib.so libc.lib.so libc_log.lib.so libc_rom.lib.so libm.lib.so pthread.lib.so zlib.lib.so sdl.lib.so
avfilter.lib.so avutil.lib.so avcodec.lib.so avformat.lib.so swscale.lib.so
mediafile
@@ -85,6 +143,7 @@ set boot_modules {
lappend_if [have_spec linux] boot_modules fb_sdl
lappend_if [have_spec pci] boot_modules pci_drv
+lappend_if [have_spec pci] boot_modules acpi_drv
lappend_if [have_spec vesa] boot_modules vesa_drv
lappend_if [have_spec ps2] boot_modules ps2_drv
diff --git a/libports/src/lib/sdl/audio/SDL_genodeaudio.cc b/libports/src/lib/sdl/audio/SDL_genodeaudio.cc
index 8b87d5ab2f..fbbad5022f 100644
--- a/libports/src/lib/sdl/audio/SDL_genodeaudio.cc
+++ b/libports/src/lib/sdl/audio/SDL_genodeaudio.cc
@@ -1,6 +1,7 @@
/*
* \brief Genode-specific audio backend
* \author Christian Prochaska
+ * \author Sebastian Sumpf
* \date 2012-03-13
*
* based on the dummy SDL audio driver
@@ -16,14 +17,12 @@
#include
#include
#include
-#include
+#include
#include
+
enum {
- AUDIO_OUT_SAMPLE_SIZE = sizeof(float),
- AUDIO_OUT_CHANNELS = 2,
- AUDIO_OUT_FREQ = 44100,
- AUDIO_OUT_SAMPLES = 1024,
+ AUDIO_CHANNELS = 2,
};
using Genode::env;
@@ -52,15 +51,11 @@ extern "C" {
/* The tag name used by Genode audio */
#define GENODEAUD_DRIVER_NAME "genode"
-typedef Audio_out::Session::Channel::Source Stream;
-
struct SDL_PrivateAudioData {
- Uint8 *mixbuf;
- Uint32 mixlen;
- Genode::Allocator_avl *block_alloc[AUDIO_OUT_CHANNELS];
- Audio_out::Connection *audio_out[AUDIO_OUT_CHANNELS];
- Stream *stream[AUDIO_OUT_CHANNELS];
+ Uint8 *mixbuf;
+ Uint32 mixlen;
+ Audio_out::Connection *audio[AUDIO_CHANNELS];
};
@@ -82,7 +77,10 @@ static void read_config()
/* read volume from config file */
try {
unsigned int config_volume;
- Genode::config()->xml_node().sub_node("sdl_audio_volume").attribute("value").value(&config_volume);
+
+ Genode::config()->xml_node().sub_node("sdl_audio_volume")
+ .attribute("value").value(&config_volume);
+
volume = (float)config_volume / 100;
}
catch (Genode::Config::Invalid) { }
@@ -108,10 +106,8 @@ static int GENODEAUD_Available(void)
static void GENODEAUD_DeleteDevice(SDL_AudioDevice *device)
{
- for (int channel = 0; channel < AUDIO_OUT_CHANNELS; channel++) {
- destroy(env()->heap(), device->hidden->audio_out[channel]);
- destroy(env()->heap(), device->hidden->block_alloc[channel]);
- }
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++)
+ destroy(env()->heap(), device->hidden->audio[channel]);
SDL_free(device->hidden);
SDL_free(device);
@@ -148,23 +144,19 @@ static SDL_AudioDevice *GENODEAUD_CreateDevice(int devindex)
_this->free = GENODEAUD_DeleteDevice;
/* connect to 'Audio_out' service */
- for (int channel = 0; channel < AUDIO_OUT_CHANNELS; channel++) {
- _this->hidden->block_alloc[channel] = new (env()->heap()) Allocator_avl(env()->heap());
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++) {
try {
- _this->hidden->audio_out[channel] = new (env()->heap())
- Audio_out::Connection(channel_names[channel], _this->hidden->block_alloc[channel]);
- _this->hidden->stream[channel] = _this->hidden->audio_out[channel]->stream();
+ _this->hidden->audio[channel] = new (env()->heap())
+ Audio_out::Connection(channel_names[channel]);
+ _this->hidden->audio[channel]->start();
} catch(Genode::Parent::Service_denied) {
PERR("Could not connect to 'Audio_out' service.");
- destroy(env()->heap(), _this->hidden->block_alloc[channel]);
- while(--channel > 0) {
- destroy(env()->heap(), _this->hidden->audio_out[channel]);
- destroy(env()->heap(), _this->hidden->block_alloc[channel]);
- }
+
+ while(--channel > 0)
+ destroy(env()->heap(), _this->hidden->audio[channel]);
+
return NULL;
}
- if (channel > 0)
- _this->hidden->audio_out[channel]->sync_session(_this->hidden->audio_out[channel-1]->session_capability());
}
Genode::config()->sigh(signal_receiver()->manage(&config_signal_context));
@@ -183,27 +175,32 @@ AudioBootStrap GENODEAUD_bootstrap = {
/* This function waits until it is possible to write a full sound buffer */
static void GENODEAUD_WaitAudio(_THIS)
{
- for (int channel = 0; channel < AUDIO_OUT_CHANNELS; channel++)
- while (_this->hidden->stream[channel]->ack_avail() ||
- !_this->hidden->stream[channel]->ready_to_submit()) {
- _this->hidden->stream[channel]->release_packet(_this->hidden->stream[channel]->get_acked_packet());
- }
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++) {
+ Audio_out::Connection *connection = _this->hidden->audio[channel];
+
+ /* wait until allocation is possible */
+ if (connection->stream()->full())
+ connection->wait_for_alloc();
+ }
}
static void GENODEAUD_PlayAudio(_THIS)
{
- Packet_descriptor p[AUDIO_OUT_CHANNELS];
+ Audio_out::Packet *p[AUDIO_CHANNELS];
+
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++)
+ while (1) {
+ Audio_out::Connection *connection = _this->hidden->audio[channel];
- for (int channel = 0; channel < AUDIO_OUT_CHANNELS; channel++)
- while (1)
try {
- p[channel] = _this->hidden->stream[channel]->alloc_packet(AUDIO_OUT_SAMPLE_SIZE * AUDIO_OUT_SAMPLES);
+ p[channel] = connection->stream()->alloc();
break;
- } catch (Stream::Packet_alloc_failed) {
+ } catch (Audio_out::Stream::Alloc_failed) {
/* wait for next finished packet */
- _this->hidden->stream[channel]->release_packet(_this->hidden->stream[channel]->get_acked_packet());
+ connection->wait_for_alloc();
}
+ }
if (signal_receiver()->pending()) {
signal_receiver()->wait_for_signal();
@@ -211,13 +208,13 @@ static void GENODEAUD_PlayAudio(_THIS)
read_config();
}
- for (int sample = 0; sample < AUDIO_OUT_SAMPLES; sample++)
- for (int channel = 0; channel < AUDIO_OUT_CHANNELS; channel++)
- _this->hidden->stream[channel]->packet_content(p[channel])[sample] =
- volume * (float)(((int16_t*)_this->hidden->mixbuf)[sample * AUDIO_OUT_CHANNELS + channel]) / 32768;
+ for (int sample = 0; sample < Audio_out::PERIOD; sample++)
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++)
+ p[channel]->content()[sample] =
+ volume * (float)(((int16_t*)_this->hidden->mixbuf)[sample * AUDIO_CHANNELS + channel]) / 32768;
- for (int channel = 0; channel < AUDIO_OUT_CHANNELS; channel++)
- _this->hidden->stream[channel]->submit_packet(p[channel]);
+ for (int channel = 0; channel < AUDIO_CHANNELS; channel++)
+ _this->hidden->audio[channel]->submit(p[channel]);
}
@@ -243,10 +240,10 @@ static int GENODEAUD_OpenAudio(_THIS, SDL_AudioSpec *spec)
PDBG("requested samples = %u", spec->samples);
PDBG("requested size = %u", spec->size);
- spec->channels = AUDIO_OUT_CHANNELS;
+ spec->channels = AUDIO_CHANNELS;
spec->format = AUDIO_S16LSB;
- spec->freq = AUDIO_OUT_FREQ;
- spec->samples = AUDIO_OUT_SAMPLES;
+ spec->freq = Audio_out::SAMPLE_RATE;
+ spec->samples = Audio_out::PERIOD;
SDL_CalculateAudioSpec(spec);
/* Allocate mixing buffer */
diff --git a/os/run/mixer.run b/os/run/mixer.run
new file mode 100644
index 0000000000..e25dee3461
--- /dev/null
+++ b/os/run/mixer.run
@@ -0,0 +1,144 @@
+#
+# Build
+#
+
+# generic components
+set build_components {
+ core init
+ drivers/timer
+ server/mixer
+ test/audio_out
+}
+
+# platform-specific components
+if {[have_spec linux]} {
+ lappend build_components drivers/audio_out
+} else {
+ lappend build_components drivers/pci
+ lappend build_components drivers/acpi
+ lappend build_components drivers/oss
+}
+
+build $build_components
+create_boot_directory
+
+
+#
+# Config
+#
+
+set config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+if {![have_spec linux]} {
+ append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+} else {
+ append config {
+
+
+
+
+
+
+ }
+}
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sample.raw
+ vogel.f32
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+
+#
+# Boot modules
+#
+
+# generic modules
+set boot_modules {
+ core init
+ timer
+ test-audio_out
+ sample.raw
+ vogel.f32
+ mixer
+}
+
+# platform-specific components
+if {[have_spec linux]} {
+ lappend boot_modules audio_out_drv
+} else {
+ lappend boot_modules oss_drv
+ lappend boot_modules acpi_drv
+ lappend boot_modules pci_drv
+}
+
+build_boot_image $boot_modules
+append qemu_args "-m 256 -soundhw es1370 -nographic"
+run_genode_until forever
diff --git a/os/src/drivers/audio_out/linux/alsa.c b/os/src/drivers/audio_out/linux/alsa.c
index 6a7d705f09..993b24d89c 100644
--- a/os/src/drivers/audio_out/linux/alsa.c
+++ b/os/src/drivers/audio_out/linux/alsa.c
@@ -39,13 +39,13 @@ int audio_drv_init(void)
if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
return -5;
- if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, &rate, 0)) < 0)
+ if ((err = snd_pcm_hw_params_set_rate(playback_handle, hw_params, rate, 0)) < 0)
return -6;
if ((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)) < 0)
return -7;
- if ((err = snd_pcm_hw_params_set_period_size(playback_handle, hw_params, 4096, 0)) < 0)
+ if ((err = snd_pcm_hw_params_set_period_size(playback_handle, hw_params, 2048, 0)) < 0)
return -8;
if ((err = snd_pcm_hw_params_set_periods(playback_handle, hw_params, 4, 0)) < 0)
diff --git a/os/src/drivers/audio_out/linux/main.cc b/os/src/drivers/audio_out/linux/main.cc
index 3132b08864..2d98162de0 100644
--- a/os/src/drivers/audio_out/linux/main.cc
+++ b/os/src/drivers/audio_out/linux/main.cc
@@ -1,9 +1,12 @@
/*
- * \brief Audio-out driver for Linux
+ * \brief Audio_out-out driver for Linux
* \author Christian Helmuth
+ * \author Sebastian Sumpf
* \date 2010-05-11
*
* FIXME session and driver shutdown not implemented (audio_drv_stop)
+ *
+ * 2013-01-09: Adapted to news audio interface
*/
/*
@@ -17,7 +20,7 @@
#include
#include
#include
-#include
+#include
#include
#include "alsa.h"
@@ -26,222 +29,242 @@ using namespace Genode;
static const bool verbose = false;
-namespace Audio_out {
+enum Channel_number { LEFT, RIGHT, MAX_CHANNELS, INVALID = MAX_CHANNELS };
- class Session_component;
-
- enum Channel_number { LEFT, RIGHT, MAX_CHANNELS, INVALID = MAX_CHANNELS };
+namespace Audio_out
+{
+ class Session_component;
+ class Out;
+ class Root;
+ struct Root_policy;
static Session_component *channel_acquired[MAX_CHANNELS];
- static Semaphore channel_sema;
+};
- class Session_component : public Session_rpc_object
- {
- private:
+class Audio_out::Session_component : public Audio_out::Session_rpc_object
+{
+ private:
- Ram_dataspace_capability _ds;
- Channel_number _channel;
+ Channel_number _channel;
- Ram_dataspace_capability _alloc_dataspace(size_t size)
- {
- _ds = env()->ram_session()->alloc(size);
- return _ds;
- }
+ public:
- public:
-
- Session_component(Channel_number channel, size_t buffer_size,
- Rpc_entrypoint &ep)
- :
- Session_rpc_object(_alloc_dataspace(buffer_size), ep),
- _channel(channel)
- {
- Audio_out::channel_acquired[_channel] = this;
- channel_sema.up();
- }
-
- ~Session_component()
- {
- channel_sema.down();
- Audio_out::channel_acquired[_channel] = 0;
-
- env()->ram_session()->free(_ds);
- }
-
-
- /*********************************
- ** Audio-out session interface **
- *********************************/
-
- void flush()
- {
- while (channel()->packet_avail())
- channel()->acknowledge_packet(channel()->get_packet());
- }
-
- void sync_session(Session_capability audio_out_session) { }
- };
-
- static bool channel_number_from_string(const char *name,
- Channel_number *out_number)
- {
- static struct Names {
- const char *name;
- Channel_number number;
- } names[] = {
- { "left", LEFT }, { "front left", LEFT },
- { "right", RIGHT }, { "front right", RIGHT },
- { 0, INVALID }
- };
-
- for (Names *n = names; n->name; ++n)
- if (!strcmp(name, n->name)) {
- *out_number = n->number;
- return true;
- }
-
- return false;
- }
-
- /**
- * Session creation policy for our service
- */
- struct Root_policy
- {
- void aquire(const char *args)
+ Session_component(Channel_number channel, Signal_context_capability data_cap)
+ :
+ Session_rpc_object(data_cap),
+ _channel(channel)
{
- size_t ram_quota =
- Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
- size_t buffer_size =
- Arg_string::find_arg(args, "buffer_size").ulong_value(0);
- size_t session_size =
- align_addr(sizeof(Session_component), 12);
-
- if ((ram_quota < session_size) ||
- (buffer_size > ram_quota - session_size)) {
- PERR("insufficient 'ram_quota', got %zd, need %zd",
- ram_quota, buffer_size + session_size);
- throw Root::Quota_exceeded();
- }
-
- char channel_name[16];
- Channel_number channel_number;
- Arg_string::find_arg(args, "channel").string(channel_name,
- sizeof(channel_name),
- "left");
- if (!channel_number_from_string(channel_name, &channel_number))
- throw Root::Invalid_args();
- if (channel_acquired[channel_number])
- throw Root::Unavailable();
+ Audio_out::channel_acquired[_channel] = this;
}
- void release() { }
+ ~Session_component()
+ {
+ Audio_out::channel_acquired[_channel] = 0;
+ }
+};
+
+
+static bool channel_number_from_string(const char *name,
+ Channel_number *out_number)
+{
+ static struct Names {
+ const char *name;
+ Channel_number number;
+ } names[] = {
+ { "left", LEFT }, { "front left", LEFT },
+ { "right", RIGHT }, { "front right", RIGHT },
+ { 0, INVALID }
};
- typedef Root_component Root_component;
+ for (Names *n = names; n->name; ++n)
+ if (!strcmp(name, n->name)) {
+ *out_number = n->number;
+ return true;
+ }
- /*
- * Root component, handling new session requests.
- */
- class Root : public Root_component,
- private Thread<0x2000>
- {
- private:
-
- Semaphore _startup_sema; /* thread startup sync */
- Rpc_entrypoint &_channel_ep;
-
- bool _packets_available(Session_component *channel)
- {
- if (channel && channel->channel()->packet_avail())
- return true;
- else
- return false;
- }
-
- void entry()
- {
- audio_drv_adopt_myself();
-
- /* indicate thread-startup completion */
- _startup_sema.up();
-
- /* handle audio-out packets */
- while (true) {
- for (int i = 0; i < MAX_CHANNELS; ++i)
- channel_sema.down();
-
- Session_component *left = channel_acquired[LEFT],
- *right = channel_acquired[RIGHT];
-
- /* get packets for channels */
- Packet_descriptor p[MAX_CHANNELS];
- static short data[2 * PERIOD];
-
- p[LEFT] = left->channel()->get_packet();
- for (int i = 0; i < 2 * PERIOD; i += 2)
- data[i] = left->channel()->packet_content(p[LEFT])[i / 2] * 32767;
- p[RIGHT] = right->channel()->get_packet();
- for (int i = 1; i < 2 * PERIOD; i += 2)
- data[i] = right->channel()->packet_content(p[RIGHT])[i / 2] * 32767;
-
- 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();
- }
-
- /* acknowledge packet to the client */
- if (p[LEFT].valid())
- left->channel()->acknowledge_packet(p[LEFT]);
- if (p[RIGHT].valid())
- right->channel()->acknowledge_packet(p[RIGHT]);
-
- for (int i = 0; i < MAX_CHANNELS; ++i)
- channel_sema.up();
- }
-
- }
-
- protected:
-
- Session_component *_create_session(const char *args)
- {
- size_t buffer_size =
- Arg_string::find_arg(args, "buffer_size").ulong_value(0);
-
- char channel_name[16];
- Channel_number channel_number = INVALID;
- Arg_string::find_arg(args, "channel").string(channel_name,
- sizeof(channel_name),
- "left");
- channel_number_from_string(channel_name, &channel_number);
-
- return new (md_alloc())
- Session_component(channel_number, buffer_size, _channel_ep);
- }
-
- public:
-
- Root(Rpc_entrypoint *session_ep, Allocator *md_alloc)
- : Root_component(session_ep, md_alloc), _channel_ep(*session_ep)
- {
- /* synchronize with root thread startup */
- start();
- _startup_sema.down();
- }
- };
+ return false;
}
+
/*
- * Manually initialize the 'lx_environ' pointer, needed because 'nic_drv' is not
- * using the normal Genode startup code.
+ * Root component, handling new session requests.
+ */
+class Audio_out::Out : public Thread<1024 * sizeof(addr_t)>
+{
+ private:
+
+ Signal_receiver *_data_recv; /* data is available */
+
+ bool _active() {
+ return channel_acquired[LEFT] && channel_acquired[RIGHT] &&
+ channel_acquired[LEFT]->active() && channel_acquired[RIGHT]->active();
+ }
+
+ Stream *left() { return channel_acquired[LEFT]->stream(); }
+ Stream *right() { return channel_acquired[RIGHT]->stream(); }
+
+ void _advance_position(Packet *l, Packet *r)
+ {
+ bool full_left = left()->full();
+ bool full_right = right()->full();
+
+ left()->pos(left()->packet_position(l));
+ right()->pos(right()->packet_position(l));
+
+ left()->increment_position();
+ right()->increment_position();
+
+ Session_component *channel_left = channel_acquired[LEFT];
+ Session_component *channel_right = channel_acquired[RIGHT];
+
+ if (full_left)
+ channel_left->alloc_submit();
+
+ if (full_right)
+ channel_right->alloc_submit();
+
+ channel_left->progress_submit();
+ channel_right->progress_submit();
+ }
+
+ bool _play_packet()
+ {
+ 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;
+ }
+
+ 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;
+ }
+
+ public:
+
+ Out(Signal_receiver *data_recv)
+ : Thread("audio_out"), _data_recv(data_recv) { }
+
+ void entry()
+ {
+ audio_drv_adopt_myself();
+
+ /* handle audio out */
+ while (true)
+ if (!_active() || !_play_packet())
+ _data_recv->wait_for_signal();
+ }
+};
+
+
+/**
+ * Session creation policy for our service
+ */
+struct Audio_out::Root_policy
+{
+ void aquire(const char *args)
+ {
+ size_t ram_quota =
+ Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
+ size_t session_size =
+ align_addr(sizeof(Audio_out::Session_component), 12);
+
+ if ((ram_quota < session_size) ||
+ (sizeof(Stream) > ram_quota - session_size)) {
+ PERR("insufficient 'ram_quota', got %zd, need %zd",
+ ram_quota, sizeof(Stream) + session_size);
+ throw ::Root::Quota_exceeded();
+ }
+
+ char channel_name[16];
+ Channel_number channel_number;
+ Arg_string::find_arg(args, "channel").string(channel_name,
+ sizeof(channel_name),
+ "left");
+ if (!channel_number_from_string(channel_name, &channel_number))
+ throw ::Root::Invalid_args();
+ if (Audio_out::channel_acquired[channel_number])
+ throw ::Root::Unavailable();
+ }
+
+ void release() { }
+};
+
+
+namespace Audio_out {
+ typedef Root_component Root_component;
+}
+
+
+class Audio_out::Root : public Audio_out::Root_component
+{
+ private:
+
+ Signal_context_capability _data_cap;
+
+ protected:
+
+ Session_component *_create_session(const char *args)
+ {
+ char channel_name[16];
+ Channel_number channel_number = INVALID;
+ Arg_string::find_arg(args, "channel").string(channel_name,
+ sizeof(channel_name),
+ "left");
+ channel_number_from_string(channel_name, &channel_number);
+
+ return new (md_alloc())
+ Session_component(channel_number, _data_cap);
+ }
+
+ public:
+
+ Root(Rpc_entrypoint *session_ep, Allocator *md_alloc, Signal_context_capability data_cap)
+ : Root_component(session_ep, md_alloc), _data_cap(data_cap)
+ { }
+};
+
+
+/*
+ * Manually initialize the 'lx_environ' pointer, needed because 'nic_drv' is
+ * not using the normal Genode startup code.
*/
extern char **environ;
char **lx_environ = environ;
@@ -249,9 +272,10 @@ char **lx_environ = environ;
int main(int argc, char **argv)
{
- enum { STACK_SIZE = 4096 };
- static Cap_connection cap;
- static Rpc_entrypoint ep(&cap, STACK_SIZE, "audio_ep");
+ /* 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));
/* init ALSA */
int err = audio_drv_init();
@@ -261,9 +285,18 @@ int main(int argc, char **argv)
}
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");
+
/* setup service */
- static Audio_out::Root audio_root(&ep, env()->heap());
+ static Audio_out::Root audio_root(&ep, env()->heap(), data_cap);
env()->parent()->announce(ep.manage(&audio_root));
+
sleep_forever();
return 0;
}
diff --git a/os/src/server/mixer/mixer.cc b/os/src/server/mixer/mixer.cc
index d5348b0735..9df8df353e 100644
--- a/os/src/server/mixer/mixer.cc
+++ b/os/src/server/mixer/mixer.cc
@@ -1,14 +1,11 @@
/*
- * \brief Audio Mixer
+ * \brief Audio_out Mixer
* \author Sebastian Sumpf
- * \author Christian Helmuth
- * \author Stefan Kalkowski
- * \date 2009-12-02
+ * \date 2012-12-20
*
- * The mixer supports up to MAX_TRACKS (virtual) two-channel stereo input
- * sessions and, therefore, provides audio-out sessions for "front left" and
- * "front right". The mixer itself uses two audio-out sessions - front left and
- * right.
+ * The mixer impelements the audio session on the server side. For each channel
+ * (currently 'left' and 'right' only) it supports multiple client sessions and
+ * mixes its input into a single client audio session.
*/
/*
@@ -18,675 +15,401 @@
* under the terms of the GNU General Public License version 2.
*/
+#include
#include
#include
-#include
-#include
-#include
-#include
+#include
+#include
#include
-#include
-#include
+#include
+#include
using namespace Genode;
-static const bool verbose = false;
-static bool audio_out_active = false;
-static Genode::Lock session_lock;
-static Rpc_entrypoint *audio_out_ep()
+static bool verbose = false;
+
+enum Channel_number { LEFT, RIGHT, MAX_CHANNELS };
+
+
+namespace Audio_out
{
- static Cap_connection cap;
-
- enum { STACK_SIZE = 4096 };
- static Rpc_entrypoint _audio_out_ep(&cap, STACK_SIZE, "audio_ep");
-
- return &_audio_out_ep;
+ class Session_elem;
+ class Session_component;
+ class Root;
+ class Channel;
+ class Mixer;
}
+static Audio_out::Channel *_channels[MAX_CHANNELS];
+
+
+static int channel_number_from_string(const char *name)
+{
+ static struct Names {
+ const char *name;
+ Channel_number number;
+ } names[] = {
+ { "left", LEFT }, { "front left", LEFT },
+ { "right", RIGHT }, { "front right", RIGHT },
+ { 0, MAX_CHANNELS }
+ };
+
+ for (Names *n = names; n->name; ++n)
+ if (!strcmp(name, n->name))
+ return n->number;
+
+ return -1;
+}
+
+
+/**
+ * Makes audio a list element
+ */
+struct Audio_out::Session_elem : Audio_out::Session_rpc_object,
+ List::Element
+{
+ Session_elem(Signal_context_capability data_cap)
+ : Session_rpc_object(data_cap) { }
+};
+
+
+/**
+ * One channel containing multiple sessions
+ */
+class Audio_out::Channel
+{
+ private:
+
+ List _list;
+
+ public:
+
+ void insert(Session_elem *session) {
+ _list.insert(session); }
+
+ Session_elem *first() {
+ return _list.first();
+ }
+};
+
+
+/**
+ * The mixer
+ */
+class Audio_out::Mixer : public Thread<1024 * sizeof(addr_t)>
+{
+ private:
+
+ Lock _sleep_lock;
+
+ Connection _left; /* left output */
+ Connection _right; /* right output */
+ Connection *_out[MAX_CHANNELS];
+
+ Signal_receiver *_data_recv; /* data availble signal receiver
+ (send from clients) */
+
+ void _sleep() { _sleep_lock.lock(); }
+
+ Mixer()
+ :
+ Thread("mixer"),
+ _sleep_lock(Lock::LOCKED), _left("left", false, true),
+ _right("right", false, true)
+ {
+ _out[LEFT] = &_left;
+ _out[RIGHT] = &_right;
+ start();
+ }
+
+ /* check for active sessions */
+ bool _check_active()
+ {
+ bool active = false;
+ for (int i = 0; i < MAX_CHANNELS; i++) {
+ Session_elem *session = _channels[i]->first();
+ while (session) {
+ active |= session->active();
+ session = session->next();
+ }
+ }
+ return active;
+ }
+
+ void _advance_session(Session_elem *session, unsigned pos)
+ {
+ if (session->stopped())
+ return;
+
+ Stream *stream = session->stream();
+ bool full = stream->full();
+
+ /* mark packets as played and icrement position pointer */
+ while (stream->pos() != pos) {
+ stream->get(stream->pos())->mark_as_played();
+ stream->increment_position();
+ }
+
+ /* send 'progress' sginal */
+ session->progress_submit();
+
+ /* send 'alloc' signal */
+ if (full)
+ session->alloc_submit();
+ }
+
+ /* advance 'positions' of all client sessions */
+ void _advance_position()
+ {
+ for (int i = 0; i < MAX_CHANNELS; i++) {
+ Session_elem *session = _channels[i]->first();
+ unsigned pos = _out[i]->stream()->pos();
+ while (session) {
+ _advance_session(session, pos);
+ session = session->next();
+ }
+ }
+ }
+
+ /* mix one packet */
+ void _mix_packet(Packet *out, Packet *in, bool clear)
+ {
+ /* when clear is set, set input an zero out remainder */
+ if (clear) {
+ out->content(in->content(), PERIOD);
+ } else {
+ /* mix */
+ for (int i = 0; i < PERIOD; i++) {
+ out->content()[i] += in->content()[i];
+
+ if (out->content()[i] > 1) out->content()[i] = 1;
+ if (out->content()[i] < -1) out->content()[i] = -1;
+ }
+ }
+ /* mark packet as processed */
+ in->invalidate();
+ }
+
+ /* get packet at offset */
+ Packet *session_packet(Session *session, unsigned offset)
+ {
+ Stream *s = session->stream();
+ return s->get(s->pos() + offset);
+ }
+
+ /* mix all session of one channel */
+ bool _mix_channel(Channel_number nr, unsigned out_pos, unsigned offset)
+ {
+ Stream *out_stream = _out[nr]->stream();
+ Packet *out = out_stream->get(out_pos + offset);
+
+ bool clear = true;
+ bool mix_all = false;
+ bool out_valid = out->valid();
+
+ for (Session_elem *session = _channels[nr]->first();
+ session;
+ session = session->next()) {
+
+ if (session->stopped())
+ continue;
+
+ Packet *in = session_packet(session, offset);
+
+ /*
+ * When there already is an out packet, start over and mix
+ * everything.
+ */
+ if (in->valid() && out_valid && !mix_all) {
+ clear = true;
+ mix_all = true;
+ session = _channels[nr]->first();
+ in = session_packet(session, offset);
+ }
+
+ /* skip if packet has been processed or was already played */
+ if ((!in->valid() && !mix_all) || in->played())
+ continue;
+
+ _mix_packet(out, in, clear);
+
+ if (verbose)
+ PDBG("mix: ch %u in %u -> out %u all %d o: %u",
+ nr, session->stream()->packet_position(in),
+ out_stream->packet_position(out), mix_all, offset);
+
+ clear = false;
+ }
+
+ return !clear;
+ }
+
+ void _mix()
+ {
+ unsigned pos[MAX_CHANNELS];
+ pos[LEFT] = _out[LEFT]->stream()->pos();
+ pos[RIGHT] = _out[RIGHT]->stream()->pos();
+
+ /*
+ * Look for packets that are valid, mix channels in an alternating
+ * way.
+ */
+ for (int i = 0; i < QUEUE_SIZE; i++) {
+ bool mix_one = true;
+ for (int j = LEFT; j < MAX_CHANNELS; j++)
+ mix_one &= _mix_channel((Channel_number)j, pos[j], i);
+
+ if (mix_one) {
+ _out[LEFT]->submit(_out[LEFT]->stream()->get(pos[LEFT] + i));
+ _out[RIGHT]->submit(_out[RIGHT]->stream()->get(pos[RIGHT] + i));
+ }
+ }
+ }
+
+ #define FOREACH_CHANNEL(func) ({ \
+ for (int i = 0; i < MAX_CHANNELS; i++) \
+ _out[i]->func(); \
+ })
+ void _wait_for_progress() { FOREACH_CHANNEL(wait_for_progress); }
+ void _start() { FOREACH_CHANNEL(start); }
+ void _stop() { FOREACH_CHANNEL(stop); }
+
+ public:
+
+ void entry()
+ {
+ _start();
+
+ while (true) {
+
+ if (!_check_active()) {
+ _stop();
+ _sleep();
+ _start();
+ continue;
+ }
+
+ _mix();
+
+ /* advance position of clients */
+ _advance_position();
+
+ if (!_left.stream()->empty())
+ _wait_for_progress();
+ else
+ _data_recv->wait_for_signal();
+ }
+ }
+
+ void wakeup() { _sleep_lock.unlock(); }
+
+ /* sync client position with output position */
+ void sync_pos(Channel_number channel, Stream *stream) {
+ stream->pos(_out[channel]->stream()->pos()); }
+
+ void data_recv(Signal_receiver *recv) { _data_recv = recv; }
+
+ static Mixer *m()
+ {
+ static Mixer _m;
+ return &_m;
+ }
+};
+
+
+class Audio_out::Session_component : public Audio_out::Session_elem
+{
+ private:
+
+ Channel_number _channel;
+
+ public:
+
+ Session_component(Channel_number channel,
+ Signal_context_capability data_cap)
+ : Session_elem(data_cap), _channel(channel) { }
+
+ void start()
+ {
+ Session_rpc_object::start();
+ /* sync audio position with mixer */
+ Mixer::m()->sync_pos(_channel, stream());
+ Mixer::m()->wakeup();
+ }
+};
+
+
namespace Audio_out {
-
- enum { OUT_QUEUE_SIZE = 1 };
-
- template
- class Ring
- {
- private:
-
- LT *_next;
- LT *_prev;
-
- public:
-
- Ring()
- : _next(static_cast(this)),
- _prev(static_cast(this)) { }
-
- LT *next() { return _next; };
- LT *prev() { return _prev; };
-
- /**
- * Conflate with another ring.
- */
- bool conflate(LT *le)
- {
- /* test whether the given ring is part of this one */
- LT *e = static_cast(this);
- while (e->Ring::_next != this) {
- if (e->Ring::_next == le)
- return false;
- e = e->Ring::_next;
- }
-
- /* wire this->next with le->prev */
- _next->Ring::_prev = le->Ring::_prev;
- le->Ring::_prev->Ring::_next = _next;
- _next = le;
- le->Ring::_prev = static_cast(this);
- return true;
- }
-
- /**
- * Remove this object from the ring.
- */
- void remove()
- {
- _prev->Ring::_next = _next;
- _next->Ring::_prev = _prev;
- _next = static_cast(this);
- _prev = static_cast(this);
- }
- };
-
- enum Channel_number { LEFT, RIGHT, MAX_CHANNELS, INVALID = MAX_CHANNELS };
-
- static bool channel_number_from_string(const char *name,
- Channel_number *out_number)
- {
- static struct Names {
- const char *name;
- Channel_number number;
- } names[] = {
- { "left", LEFT }, { "front left", LEFT },
- { "right", RIGHT }, { "front right", RIGHT },
- { 0, INVALID }
- };
-
- for (Names *n = names; n->name; ++n)
- if (!strcmp(name, n->name)) {
- *out_number = n->number;
- return true;
- }
-
- return false;
- }
-
- static const char * channel_string_from_number(Channel_number number)
- {
- static const char *names[MAX_CHANNELS + 1] = {
- "front left", "front right", "invalid"
- };
-
- return names[number];
- }
-
- static Semaphore open_tracks;
- static int num_open_tracks[MAX_CHANNELS];
-
- /*
- * The mixer uses only one signal receiver and context for all input
- * tracks.
- */
- static Signal_receiver avail_recv;
- static Signal_context avail_ctx;
- static Signal_context_capability avail_cap(avail_recv.manage(&avail_ctx));
-
- enum { MAX_TRACKS = 16 };
-
-
- class Communication_buffer : Ram_dataspace_capability
- {
- public:
-
- Communication_buffer(size_t size)
- : Ram_dataspace_capability(env()->ram_session()->alloc(size))
- { }
-
- ~Communication_buffer() { env()->ram_session()->free(*this); }
-
- Dataspace_capability dataspace() { return *this; }
- };
-
-
- class Session_component : public List::Element,
- public Ring,
- private Communication_buffer,
- public Session_rpc_object
- {
- private:
-
- Channel_number _channel;
-
- public:
-
- Session_component(Channel_number channel, size_t buffer_size,
- Rpc_entrypoint &ep)
- :
- Communication_buffer(buffer_size),
- Session_rpc_object(Communication_buffer::dataspace(), ep),
- _channel(channel)
- {
- if (verbose) PDBG("new session %p", this);
-
- track_list()->insert(this);
- num_open_tracks[_channel]++;
-
- open_tracks.up();
- }
-
- ~Session_component()
- {
- Genode::Lock::Guard lock_guard(session_lock);
- open_tracks.down();
-
- num_open_tracks[_channel]--;
- track_list()->remove(this);
- Ring::remove();
-
- if (verbose) PDBG("session %p closed", this);
- }
-
- static List *track_list()
- {
- static List _track_list;
- return &_track_list;
- }
-
- /*
- * We only need one central signal context within the mixer.
- */
- Signal_context_capability _sigh_packet_avail()
- {
- return avail_cap;
- }
-
- Channel_number channel_number() const { return _channel; }
-
- bool all_channel_packet_avail() {
- if (!channel()->packet_avail())
- return false;
-
- Session_component *s = this;
- while (s->Ring::next() != this) {
- s = s->Ring::next();
- if (!s->channel()->packet_avail())
- return false;
- }
- return true;
- }
-
- void flush()
- {
- while (channel()->packet_avail())
- channel()->acknowledge_packet(channel()->get_packet());
- }
-
- void sync_session(Session_capability audio_out_session)
- {
- Object_pool::Guard
- sc(audio_out_ep()->lookup_and_lock(audio_out_session));
-
- /* check if recipient is a valid session component */
- if (!sc) return;
-
- if (this->conflate(sc))
- track_list()->remove(this);
- }
- };
-
- /**
- * Session creation policy for our service
- */
- struct Root_policy
- {
- void aquire(const char *args)
- {
- size_t ram_quota =
- Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
- size_t buffer_size =
- Arg_string::find_arg(args, "buffer_size").ulong_value(0);
- size_t session_size =
- align_addr(sizeof(Session_component), 12);
-
- if ((ram_quota < session_size) ||
- (buffer_size > ram_quota - session_size)) {
- PERR("insufficient 'ram_quota', got %zd, need %zd",
- ram_quota, buffer_size + session_size);
- throw Root::Quota_exceeded();
- }
-
- char channel_name[16];
- Channel_number channel_number;
- Arg_string::find_arg(args, "channel").string(channel_name,
- sizeof(channel_name),
- "left");
- if (!channel_number_from_string(channel_name, &channel_number))
- throw Root::Invalid_args();
- if (!(num_open_tracks[channel_number] < MAX_TRACKS)) {
- PERR("throw");
- throw Root::Unavailable();
- }
- }
-
- void release() { }
- };
-
- typedef Root_component Root_component;
-
- class Root : public Root_component
- {
- private:
-
- Rpc_entrypoint &_channel_ep;
-
- protected:
-
- Session_component *_create_session(const char *args)
- {
- size_t buffer_size =
- Arg_string::find_arg(args, "buffer_size").ulong_value(0);
-
- char channel_name[16];
- Channel_number channel_number = INVALID;
- Arg_string::find_arg(args, "channel").string(channel_name,
- sizeof(channel_name),
- "left");
- channel_number_from_string(channel_name, &channel_number);
-
- Session_component *session = new (md_alloc())
- Session_component(channel_number, buffer_size,
- _channel_ep);
-
- PDBG("Added new \"%s\" channel %d/%d",
- channel_name, num_open_tracks[channel_number], MAX_TRACKS);
-
- return session;
- }
-
- public:
-
- Root(Rpc_entrypoint *session_ep, Allocator *md_alloc)
- : Root_component(session_ep, md_alloc), _channel_ep(*session_ep) { }
- };
-
- class Packet_cache
- {
- private:
-
- class Track_packet;
- class Channel_packet;
-
-
- typedef Tslab Track_packet_slab;
- typedef Tslab Channel_packet_slab;
-
- Track_packet_slab _track_packet_slab;
- Channel_packet_slab _channel_packet_slab;
-
- Genode::Lock _lock;
-
-
- class Track_packet : public List::Element
- {
- private:
-
- Packet_descriptor _packet;
- Session::Channel::Sink *_sink;
-
- public:
-
- Track_packet(Packet_descriptor p,
- Session::Channel::Sink *sink)
- : _packet(p), _sink(sink) {}
-
-
- bool session_active()
- {
- for (Session_component *session = Session_component::track_list()->first();
- session;
- session = session->List::Element::next())
-
- for (Session_component *sc = session;
- true;
- sc = sc->Ring::next()) {
- if (sc->channel() == _sink)
- return true;
-
- if (sc->Ring::next() == session)
- break;
- }
-
- return false;
- }
-
- void acknowledge() {
- if (session_active())
- _sink->acknowledge_packet(_packet); }
- };
-
-
- class Channel_packet : public List::Element
- {
- private:
-
- List _track_packets;
- Packet_descriptor _packet;
- Track_packet_slab *_slab;
-
- public:
-
- Channel_packet(Packet_descriptor p, Track_packet_slab *slab)
- : _packet(p), _slab(slab) { }
-
- void add(Track_packet *p) { _track_packets.insert(p); }
-
- void acknowledge()
- {
- Track_packet *p = _track_packets.first();
- while (p) {
- p->acknowledge();
- _track_packets.remove(p);
- _slab->free(p);
- p = _track_packets.first();
- }
- }
-
- bool packet(Packet_descriptor p)
- {
- return p.size() == _packet.size() &&
- p.offset() == _packet.offset();
- }
- };
-
-
- List _channel_packets[MAX_CHANNELS];
- Connection *_out_stream[MAX_CHANNELS];
-
- public:
-
- Packet_cache(Connection *output_stream[MAX_CHANNELS])
- : _track_packet_slab(Genode::env()->heap()),
- _channel_packet_slab(Genode::env()->heap())
- {
- for (int chn = 0; chn < MAX_CHANNELS; ++chn)
- _out_stream[chn] = output_stream[chn];
- }
-
- void ack_packets()
- {
- for (int chn = 0; chn < MAX_CHANNELS; ++chn) {
- Session::Channel::Source *stream = _out_stream[chn]->stream();
-
- Packet_descriptor p = stream->get_acked_packet();
-
- if (verbose) PDBG("ack channel %d", chn);
-
- Genode::Lock::Guard lock_guard(_lock);
- Channel_packet *ch_packet = _channel_packets[chn].first();
- while (ch_packet) {
- if (ch_packet->packet(p)) {
- ch_packet->acknowledge();
- _channel_packets[chn].remove(ch_packet);
- _channel_packet_slab.free(ch_packet);
- break;
- }
- ch_packet = ch_packet->next();
- }
- stream->release_packet(p);
- }
- }
-
- void put(Packet_descriptor p, Session::Channel::Sink **sinks,
- Packet_descriptor *cli_p, int count, int chn)
- {
- Genode::Lock::Guard lock_guard(_lock);
-
- Channel_packet *ch_packet = new (&_channel_packet_slab)
- Channel_packet(p, &_track_packet_slab);
- for (int i = 0; i < count; ++i) {
- Track_packet *t_packet = new (&_track_packet_slab)
- Track_packet(cli_p[i], sinks[i]);
- ch_packet->add(t_packet);
- }
- _channel_packets[chn].insert(ch_packet);
- }
- };
-
- class Mixer : private Genode::Thread<4096>
- {
- private:
-
- struct Mixer_packets
- {
- Session::Channel::Sink *sink[MAX_TRACKS];
- Packet_descriptor packet[MAX_TRACKS];
- int count;
- } _packets[MAX_CHANNELS];
-
- Connection *_out_stream[MAX_CHANNELS];
- Semaphore _packet_sema; /* packets available */
- Packet_cache *_cache;
- Semaphore _startup_sema; /* thread startup sync */
-
- class Receiver : private Genode::Thread<4096>
- {
- private:
-
- Packet_cache *_cache;
- Semaphore _startup_sema;
- Semaphore *_packet_sema;
-
- void entry()
- {
- /* indicate thread-startup completion */
- _startup_sema.up();
- while (true) {
- _cache->ack_packets();
- _packet_sema->up();
- }
- }
-
- public:
-
- Receiver(Packet_cache *cache, Semaphore *packet_sema)
- : Genode::Thread<4096>("ack"), _cache(cache),
- _packet_sema(packet_sema)
- {
- if (audio_out_active) {
- start();
- _startup_sema.down();
- }
- }
- };
-
- Receiver _receiver;
-
- bool _get_packets()
- {
- bool packet_avail = false;
-
- for (int i = 0; i < MAX_CHANNELS; ++i)
- _packets[i].count = 0;
-
- for (Session_component *session = Session_component::track_list()->first();
- session;
- session = session->List::Element::next()) {
-
- if (!session->all_channel_packet_avail())
- continue;
-
- for (Session_component *sc = session;
- true;
- sc = sc->Ring::next()) {
- Channel_number chn = sc->channel_number();
- int cnt = _packets[chn].count;
-
- _packets[chn].packet[cnt] = sc->channel()->get_packet();
- _packets[chn].sink[cnt] = sc->channel();
-
- _packets[chn].count++;
- packet_avail = true;
-
- if (sc->Ring::next() == session)
- break;
- }
- }
-
- return packet_avail;
- }
-
- Packet_descriptor _mix_one_channel(Mixer_packets *packets,
- Session::Channel::Source *stream)
- {
- static int alloc_cnt, alloc_fail_cnt;
- Packet_descriptor p;
-
- while (1)
- try {
- p = stream->alloc_packet(FRAME_SIZE * PERIOD);
- if (verbose)
- alloc_cnt++;
- break;
- } catch (Session::Channel::Source::Packet_alloc_failed) {
- PERR("Packet allocation failed %d %d",
- ++alloc_fail_cnt, alloc_cnt);
- }
-
- float *out = stream->packet_content(p);
- for (int size = 0; size < PERIOD; ++size) {
- float sample = 0;
- for (int i = 0; i < packets->count; ++i) {
- sample += packets->sink[i]->packet_content(packets->packet[i])[size];
- }
-
- if (sample > 1) sample = 1;
- if (sample < -1) sample = -1;
-
- out[size] = sample;
- }
-
- return p;
- }
-
- void _mix(Packet_descriptor p[MAX_CHANNELS])
- {
- /* block if no packets are available */
- session_lock.lock();
- while (!_get_packets()) {
- session_lock.unlock();
- avail_recv.wait_for_signal();
- session_lock.lock();
- }
- _packet_sema.down();
-
- /* mix packets */
- for (int chn = 0; chn < MAX_CHANNELS; ++chn)
- p[chn] = _mix_one_channel(&_packets[chn],
- _out_stream[chn]->stream());
- session_lock.unlock();
-
- /* put packets into packet cache */
- for (int chn = 0; chn < MAX_CHANNELS; ++chn)
- _cache->put(p[chn], _packets[chn].sink, _packets[chn].packet,
- _packets[chn].count, chn);
- }
-
- void entry()
- {
- /* indicate thread-startup completion */
- _startup_sema.up();
-
- /* just acknowledge packets if we don't have an audio out stream */
- while (!audio_out_active) {
-
- while (!_get_packets())
- avail_recv.wait_for_signal();
-
- for (int chn = 0; chn < MAX_CHANNELS; ++chn)
- for (int i = 0; i < _packets[chn].count; i++)
- _packets[chn].sink[i]->acknowledge_packet(_packets[chn].packet[i]);
- }
-
- while (1) {
- open_tracks.down();
-
- /* check and mix sources */
- Packet_descriptor p[MAX_CHANNELS];
- _mix(p);
-
- /* submit to out */
- for (int chn = 0; chn < MAX_CHANNELS; ++chn) {
- Session::Channel::Source *stream = _out_stream[chn]->stream();
-
- stream->submit_packet(p[chn]);
- }
-
- if (verbose)
- PDBG("packet submitted");
-
- open_tracks.up();
- }
- }
-
- public:
-
- Mixer(Connection *output_stream[MAX_CHANNELS], Packet_cache *cache)
- : Genode::Thread<4096>("tx"), _packet_sema(OUT_QUEUE_SIZE),
- _cache(cache), _receiver(cache, &_packet_sema)
- {
- for (int chn = 0; chn < MAX_CHANNELS; ++chn)
- _out_stream[chn] = output_stream[chn];
-
- /* synchronize with mixer thread startup */
- start();
- _startup_sema.down();
- }
- };
+ typedef Root_component Root_component;
}
-int main(int argc, char **argv)
+class Audio_out::Root : public Audio_out::Root_component
{
- PDBG("-- Genode Audio Mixer --");
+ Signal_context_capability _data_cap;
- using namespace Audio_out;
+ Session_component *_create_session(const char *args)
+ {
+ char channel_name[16];
+ Arg_string::find_arg(args, "channel").string(channel_name,
+ sizeof(channel_name),
+ "left");
+ size_t ram_quota =
+ Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
- /* setup audio-out connections for output */
- static Audio_out::Connection *output_stream[MAX_CHANNELS];
+ size_t session_size = align_addr(sizeof(Session_component), 12);
- try {
- for (int i = 0; i < MAX_CHANNELS; ++i) {
- Allocator_avl *block_alloc = new (env()->heap()) Allocator_avl(env()->heap());
- output_stream[i] = new (env()->heap())
- Audio_out::Connection(channel_string_from_number((Channel_number)i), block_alloc, OUT_QUEUE_SIZE * FRAME_SIZE * PERIOD + 0x400);
+ if ((ram_quota < session_size) ||
+ (sizeof(Stream) > ram_quota - session_size)) {
+ PERR("insufficient 'ram_quota', got %zd, need %zd",
+ ram_quota, sizeof(Stream) + session_size);
+ throw Root::Quota_exceeded();
}
- audio_out_active = true;
- } catch (...) {
- PWRN("no audio driver found - dropping incoming packets");
+
+ int ch = channel_number_from_string(channel_name);
+ if (ch < 0)
+ throw Root::Invalid_args();
+
+ Session_component *session = new (md_alloc())
+ Session_component((Channel_number)ch, _data_cap);
+
+ PDBG("Added new \"%s\" nr: %u s: %p",channel_name, ch, session);
+ _channels[ch]->insert(session);
+ return session;
}
- /* initialize packet cache */
- static Packet_cache cache(output_stream);
+ public:
- /* setup service */
- static Audio_out::Root mixer_root(audio_out_ep(), env()->heap());
- env()->parent()->announce(audio_out_ep()->manage(&mixer_root));
+ Root(Rpc_entrypoint *session_ep,
+ Signal_context_capability data_cap,
+ Allocator *md_alloc)
+ : Root_component(session_ep, md_alloc), _data_cap(data_cap) { }
+};
- /* start mixer */
- static Mixer mixer(output_stream, &cache);
+
+int main()
+{
+ static Cap_connection cap;
+ enum { STACK_SIZE = 1024 * sizeof(addr_t) };
+
+ for (int i = 0; i < MAX_CHANNELS; i++)
+ _channels[i] = new (env()->heap()) Audio_out::Channel();
+
+ static Signal_receiver data_recv;
+ static Signal_context data_context;
+ static Signal_context_capability data_cap(data_recv.manage(&data_context));
+
+ /* start mixer thread */
+ Audio_out::Mixer::m()->data_recv(&data_recv);
+
+ static Rpc_entrypoint ep(&cap, STACK_SIZE, "audio_ep");
+ static Audio_out::Root root(&ep, data_cap, env()->heap());
+ env()->parent()->announce(ep.manage(&root));
sleep_forever();
return 0;
}
+
diff --git a/os/src/test/audio_out/main.cc b/os/src/test/audio_out/main.cc
index c8329bb9d1..0900818256 100644
--- a/os/src/test/audio_out/main.cc
+++ b/os/src/test/audio_out/main.cc
@@ -15,13 +15,17 @@
* under the terms of the GNU General Public License version 2.
*/
-#include
+#include
#include
#include
-#include
-#include
+#include
+#include
#include
+
+using namespace Genode;
+
+
using namespace Genode;
using namespace Audio_out;
@@ -29,11 +33,12 @@ static const bool verbose = false;
enum {
CHN_CNT = 2, /* number of channels */
+ FRAME_SIZE = sizeof(float),
PERIOD_CSIZE = FRAME_SIZE * PERIOD, /* size of channel packet (bytes) */
PERIOD_FSIZE = CHN_CNT * PERIOD_CSIZE, /* size of period in file (bytes) */
-
};
+
static const char *channel_names[] = { "front left", "front right" };
@@ -41,22 +46,18 @@ class Track : Thread<8192>
{
private:
- typedef Audio_out::Session::Channel::Source Stream;
-
const char *_file;
Audio_out::Connection *_audio_out[CHN_CNT];
- Stream *_stream[CHN_CNT];
public:
- Track(const char *file, Allocator_avl *block_alloc[CHN_CNT]) : _file(file)
+ Track(const char *file) : Thread("track"), _file(file)
{
for (int i = 0; i < CHN_CNT; ++i) {
+ /* allocation signal for first channel only */
_audio_out[i] = new (env()->heap())
- Audio_out::Connection(channel_names[i], block_alloc[i]);
- _stream[i] = _audio_out[i]->stream();
- if (i > 0)
- _audio_out[i]->sync_session(_audio_out[i-1]->session_capability());
+ Audio_out::Connection(channel_names[i],
+ i == 0 ? true : false);
}
}
@@ -82,8 +83,9 @@ class Track : Thread<8192>
PDBG("%s size is %zu Bytes (attached to %p)",
_file, ds_client.size(), base);
- Packet_descriptor p[CHN_CNT];
- size_t file_size = ds_client.size();
+ size_t file_size = ds_client.size();
+ for (int i = 0; i < CHN_CNT; ++i)
+ _audio_out[i]->start();
while (1) {
@@ -100,46 +102,40 @@ class Track : Thread<8192>
? (file_size - offset) / CHN_CNT / FRAME_SIZE
: PERIOD;
- for (int chn = 0; chn < CHN_CNT; ++chn)
- while (1)
- try {
- p[chn] = _stream[chn]->alloc_packet(PERIOD_CSIZE);
- break;
- } catch (Stream::Packet_alloc_failed) {
- /* wait for next finished packet */
- _stream[chn]->release_packet(_stream[chn]->get_acked_packet());
- }
+ Packet *p[CHN_CNT];
+ while (1)
+ try {
+ p[0] = _audio_out[0]->stream()->alloc();
+ break;
+ } catch (Audio_out::Stream::Alloc_failed) {
+ _audio_out[0]->wait_for_alloc();
+ }
+
+ unsigned pos = _audio_out[0]->stream()->packet_position(p[0]);
+ /* sync other channels with first one */
+ for (int chn = 1; chn < CHN_CNT; ++chn)
+ p[chn] = _audio_out[chn]->stream()->get(pos);
/* copy channel contents into sessions */
float *content = (float *)(base + offset);
for (unsigned c = 0; c < CHN_CNT * chunk; c += CHN_CNT)
for (int i = 0; i < CHN_CNT; ++i)
- _stream[i]->packet_content(p[i])[c / 2] = content[c + i];
+ p[i]->content()[c / 2] = content[c + i];
/* handle last packet gracefully */
if (chunk < PERIOD) {
for (int i = 0; i < CHN_CNT; ++i)
- memset((_stream[i]->packet_content(p[i]) + chunk),
+ memset(p[i]->content() + chunk,
0, PERIOD_CSIZE - FRAME_SIZE * chunk);
}
if (verbose)
- PDBG("%s submit packet %zu", _file, cnt);
+ PDBG("%s submit packet %zu", _file,
+ _audio_out[0]->stream()->packet_position((p[0])));
- for (int i = 0; i < CHN_CNT; ++i)
- _stream[i]->submit_packet(p[i]);
-
- for (int i = 0; i < CHN_CNT; ++i)
- while (_stream[i]->ack_avail() ||
- !_stream[i]->ready_to_submit()) {
- _stream[i]->release_packet(_stream[i]->get_acked_packet());
- }
+ for (int i = 0; i < CHN_CNT; i++)
+ _audio_out[i]->submit(p[i]);
}
-
- /* ack remaining packets */
- for (int i = 0; i < CHN_CNT; ++i)
- while (_stream[i]->ack_avail())
- _stream[i]->release_packet(_stream[i]->get_acked_packet());
}
}
@@ -189,7 +185,7 @@ static int process_config(const char ***files)
int main(int argc, char **argv)
{
- PDBG("--- Audio-out test ---\n");
+ PDBG("--- Audio_out test ---\n");
const char *defaults[] = { "1.raw", "2.raw" };
const char **files = defaults;
@@ -203,11 +199,9 @@ int main(int argc, char **argv)
}
Track *track[cnt];
- Allocator_avl *block_alloc[cnt][CHN_CNT];
+
for (int i = 0; i < cnt; ++i) {
- for (int j = 0; j < CHN_CNT; ++j)
- block_alloc[i][j] = new (env()->heap()) Allocator_avl(env()->heap());
- track[i] = new (env()->heap()) Track(files[i], block_alloc[i]);
+ track[i] = new (env()->heap()) Track(files[i]);
}
/* start playback after constrution of all tracks */
@@ -217,3 +211,5 @@ int main(int argc, char **argv)
sleep_forever();
return 0;
}
+
+