From 53189122cc22d0a8522a47ebe8ee2aac64de2627 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Thu, 4 Jul 2019 15:59:57 +0200 Subject: [PATCH] mp3_audio_sink --- Tuprules.tup | 2 +- errata/runtime.xsd | 1 + index.xml | 28 +-- ports/default.nix | 1 - ports/mpg123/Tupfile | 35 ++++ ports/mpg123/arm.files | 1 + ports/mpg123/common.files | 38 ++++ ports/mpg123/config.h | 48 +++++ ports/mpg123/default.nix | 27 +++ ports/mpg123/mpg123.symbols | 115 +++++++++++ ports/mpg123/port_rules.sh | 16 ++ ports/mpg123/x86_64.files | 5 + src/mp3_audio_sink/Tupfile | 12 ++ src/mp3_audio_sink/component.cc | 352 ++++++++++++++++++++++++++++++++ 14 files changed, 665 insertions(+), 16 deletions(-) create mode 100644 ports/mpg123/Tupfile create mode 100644 ports/mpg123/arm.files create mode 100644 ports/mpg123/common.files create mode 100644 ports/mpg123/config.h create mode 100644 ports/mpg123/default.nix create mode 100644 ports/mpg123/mpg123.symbols create mode 100755 ports/mpg123/port_rules.sh create mode 100644 ports/mpg123/x86_64.files create mode 100644 src/mp3_audio_sink/Tupfile create mode 100644 src/mp3_audio_sink/component.cc diff --git a/Tuprules.tup b/Tuprules.tup index 5f4680f..57f15dd 100644 --- a/Tuprules.tup +++ b/Tuprules.tup @@ -163,7 +163,7 @@ PKG_CONFIG = PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config !cc = | $(GENODE_DIR)/ |> ^o CC %f^ @(CC_WRAPPER) $(CC) $(DEFINES) $(CFLAGS) $(CFLAGS_%e) $(CFLAGS_%f) `$(PKG_CONFIG) --cflags $(LIBS) $(LIBS_CFLAGS)` $(INCLUDES) -c %f -o %o |> %B.o -!cc_port = | $(GENODE_DIR)/ |> ^o CC %o^ @(CC_WRAPPER) $(CC) -c $(DEFINES) $(CFLAGS) $(CFLAGS_%o) $(INCLUDES) `$(PKG_CONFIG) --cflags $(LIBS) $(LIBS_CFLAGS)` -o %o |> %B.o +!cc_port = | $(GENODE_DIR)/ |> ^o CC %o^ @(CC_WRAPPER) $(CC) -c -fPIC $(DEFINES) $(CFLAGS) $(CFLAGS_%o) $(INCLUDES) `$(PKG_CONFIG) --cflags $(LIBS) $(LIBS_CFLAGS)` -o %o |> %B.o !cxx = | $(GENODE_DIR)/ |> ^o CXX %b^ @(CC_WRAPPER) $(CXX) $(DEFINES) $(CXXFLAGS) $(CXXFLAGS_%e) $(CXXFLAGS_%f) `$(PKG_CONFIG) --cflags $(LIBS)` $(INCLUDES) -c %f -o %o |> %B.o diff --git a/errata/runtime.xsd b/errata/runtime.xsd index b3e6966..760df43 100644 --- a/errata/runtime.xsd +++ b/errata/runtime.xsd @@ -19,6 +19,7 @@ + diff --git a/index.xml b/index.xml index 4a989b9..a3ccc16 100644 --- a/index.xml +++ b/index.xml @@ -1,5 +1,16 @@ + + + + + + + + + + + @@ -60,10 +71,6 @@ - - - - @@ -78,8 +85,7 @@ - - + @@ -100,26 +106,20 @@ - - - - - - - + - diff --git a/ports/default.nix b/ports/default.nix index 74e2901..ce03b45 100644 --- a/ports/default.nix +++ b/ports/default.nix @@ -5,7 +5,6 @@ let let f = (import path); in f (builtins.intersectAttrs (builtins.functionArgs f) (tool.nixpkgs // tool) ); - hasSuffixNix = tool.hasSuffix ".nix"; dir = builtins.readDir ../ports; in builtins.listToAttrs ( diff --git a/ports/mpg123/Tupfile b/ports/mpg123/Tupfile new file mode 100644 index 0000000..15781df --- /dev/null +++ b/ports/mpg123/Tupfile @@ -0,0 +1,35 @@ +TARGET_NAME = mpg123 +LIBS += libc +include_rules + +SOURCE_LINK = port-source +API_LINK = port-api + +: |> $(NIX_BUILD) .. --out-link port \ + --attr %d.source --attr %d.api |> $(SOURCE_LINK) $(API_LINK) {port} + +: $(API_LINK) |> cp %f/pkg-config/%d.pc %o \ + |> $(PKG_CONFIG_DIR)/%d.pc $(GENODE_DIR)/ + +: mpg123.symbols |> !abi_stub |> + +INCLUDES += -I. +INCLUDES += -I$(SOURCE_LINK)/src/libmpg123 +INCLUDES += -I$(SOURCE_LINK)/src/compat +INCLUDES += -I$(SOURCE_LINK)/src +INCLUDES += -I$(API_LINK)/include + +ifeq (@(TUP_ARCH),x86_64) + DEFINES += -DOPT_X86_64 + run ./port_rules.sh $(SOURCE_LINK) common.files x86_64.files +endif + +ifeq (@(TUP_ARCH),arm) + DEFINES += -DOPT_ARM + run ./port_rules.sh $(SOURCE_LINK) common.files arm.files +endif + +: {obj} |> !lib |> %d.lib.so {bin} +: {bin} |> !collect_bin |> + +include &(BIN_RULES) diff --git a/ports/mpg123/arm.files b/ports/mpg123/arm.files new file mode 100644 index 0000000..ffacb3b --- /dev/null +++ b/ports/mpg123/arm.files @@ -0,0 +1 @@ +src/libmpg123/synth_arm.S diff --git a/ports/mpg123/common.files b/ports/mpg123/common.files new file mode 100644 index 0000000..7eaf20c --- /dev/null +++ b/ports/mpg123/common.files @@ -0,0 +1,38 @@ +src/compat/compat.c +src/compat/compat_str.c +src/libmpg123/parse.c +src/libmpg123/layer1.c +src/libmpg123/synth_stereo_avx.S +src/libmpg123/feature.c +src/libmpg123/lfs_alias.c +src/libmpg123/synth_s32.c +src/libmpg123/dct64_avx.S +src/libmpg123/tabinit.c +src/libmpg123/dct64_i386.c +src/libmpg123/format.c +src/libmpg123/dct64_avx_float.S +src/libmpg123/dither.c +src/libmpg123/synth.c +src/libmpg123/synth_8bit.c +src/libmpg123/layer3.c +src/libmpg123/dct64.c +src/libmpg123/synth_stereo_avx_accurate.S +src/libmpg123/mpg123.h.in +src/libmpg123/icy.c +src/libmpg123/index.c +src/libmpg123/equalizer.c +src/libmpg123/readers.c +src/libmpg123/icy2utf8.c +src/libmpg123/stringbuf.c +src/libmpg123/synth_real.c +src/libmpg123/dct36_avx.S +src/libmpg123/testcpu.c +src/libmpg123/frame.c +src/libmpg123/id3.c +src/libmpg123/Makemodule.am +src/libmpg123/ntom.c +src/libmpg123/synth_stereo_avx_float.S +src/libmpg123/libmpg123.c +src/libmpg123/synth_stereo_avx_s32.S +src/libmpg123/layer2.c +src/libmpg123/optimize.c diff --git a/ports/mpg123/config.h b/ports/mpg123/config.h new file mode 100644 index 0000000..4d34cfd --- /dev/null +++ b/ports/mpg123/config.h @@ -0,0 +1,48 @@ +#define ASMALIGN_BALIGN 1 +#define CCALIGN 1 +#define DYNAMIC_BUILD 1 +#define FRAME_INDEX 1 +#define GAPLESS 1 +#define HAVE_ATOLL 1 +#define HAVE_DIRENT_H 1 +#define HAVE_DLCLOSE 1 +#define HAVE_DLFCN_H 1 +#define HAVE_DLOPEN 1 +#define HAVE_DLSYM 1 +#define HAVE_GETPAGESIZE 1 +#define HAVE_GETUID 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LIBM 1 +#define HAVE_LIMITS_H 1 +#define HAVE_MEMORY_H 1 +#define HAVE_RANDOM 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDIO_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRERROR 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_RESOURCE_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_SIGNAL_H 1 +#define HAVE_SYS_SOUNDCARD_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_WAIT_H 1 +#define HAVE_TERMIOS 1 +#define HAVE_UNISTD_H 1 +#define IEEE_FLOAT 1 +#define INDEX_SIZE 1000 +#define LFS_ALIAS_BITS 64 +#define SIZEOF_INT32_T 4 +#define SIZEOF_LONG 8 +#define SIZEOF_OFF_T 8 +#define SIZEOF_SIZE_T 8 +#define SIZEOF_SSIZE_T 8 +#define STDC_HEADERS 1 +#define USE_MODULES 1 +#define USE_NEW_HUFFTABLE 1 +#define lfs_alias_t off_t diff --git a/ports/mpg123/default.nix b/ports/mpg123/default.nix new file mode 100644 index 0000000..a947ec7 --- /dev/null +++ b/ports/mpg123/default.nix @@ -0,0 +1,27 @@ +{ preparePort, mpg123 }: + +let + apiVersion = 44; # found in configure.ac +in +preparePort rec { + inherit (mpg123) name src; + outputs = [ "source" "api" ]; + buildPhase = + '' + mkdir -p $api/include $api/pkg-config + + sed \ + -e 's/@API_VERSION@/$(API_VERSION)/' \ + -e '/@.*@/d' \ + src/libmpg123/mpg123.h.in > $api/include/mpg123.h + + cp src/libmpg123/fmt123.h $api/include + + sed \ + -e "s|@includedir@|$api/include|" \ + -e 's/@PACKAGE_VERSION@/${(builtins.parseDrvName name).version}/' \ + -e 's/^Libs:.*/Libs: -l:mpg123.lib.so/' \ + -e '/@/d' \ + < libmpg123.pc.in > $api/pkg-config/mpg123.pc + ''; +} diff --git a/ports/mpg123/mpg123.symbols b/ports/mpg123/mpg123.symbols new file mode 100644 index 0000000..f48c68b --- /dev/null +++ b/ports/mpg123/mpg123.symbols @@ -0,0 +1,115 @@ +mpg123_add_string T +mpg123_add_substring T +mpg123_chomp_string T +mpg123_clip T +mpg123_close T +mpg123_copy_string T +mpg123_current_decoder T +mpg123_decode T +mpg123_decode_frame T +mpg123_decode_frame_64 T +mpg123_decoder T +mpg123_decoders T +mpg123_delete T +mpg123_delete_pars T +mpg123_enc_from_id3 T +mpg123_encodings T +mpg123_encsize T +mpg123_eq T +mpg123_errcode T +mpg123_exit T +mpg123_feature T +mpg123_feed T +mpg123_feedseek T +mpg123_feedseek_64 T +mpg123_fmt T +mpg123_fmt_all T +mpg123_fmt_none T +mpg123_fmt_support T +mpg123_format T +mpg123_format_all T +mpg123_format_none T +mpg123_format_support T +mpg123_framebyframe_decode T +mpg123_framebyframe_decode_64 T +mpg123_framebyframe_next T +mpg123_framedata T +mpg123_framelength T +mpg123_framelength_64 T +mpg123_framepos T +mpg123_framepos_64 T +mpg123_free_string T +mpg123_geteq T +mpg123_getformat T +mpg123_getformat2 T +mpg123_getpar T +mpg123_getparam T +mpg123_getstate T +mpg123_getvolume T +mpg123_grow_string T +mpg123_icy T +mpg123_icy2utf8 T +mpg123_id3 T +mpg123_index T +mpg123_index_64 T +mpg123_info T +mpg123_init T +mpg123_init_string T +mpg123_length T +mpg123_length_64 T +mpg123_meta_check T +mpg123_meta_free T +mpg123_new T +mpg123_new_pars T +mpg123_noise T +mpg123_open T +mpg123_open_64 T +mpg123_open_fd T +mpg123_open_fd_64 T +mpg123_open_feed T +mpg123_open_handle T +mpg123_open_handle_64 T +mpg123_outblock T +mpg123_par T +mpg123_param T +mpg123_parnew T +mpg123_plain_strerror T +mpg123_position T +mpg123_position_64 T +mpg123_rates T +mpg123_read T +mpg123_replace_buffer T +mpg123_replace_reader T +mpg123_replace_reader_64 T +mpg123_replace_reader_handle T +mpg123_replace_reader_handle_64 T +mpg123_reset_eq T +mpg123_resize_string T +mpg123_safe_buffer T +mpg123_scan T +mpg123_seek T +mpg123_seek_64 T +mpg123_seek_frame T +mpg123_seek_frame_64 T +mpg123_set_filesize T +mpg123_set_filesize_64 T +mpg123_set_index T +mpg123_set_index_64 T +mpg123_set_string T +mpg123_set_substring T +mpg123_spf T +mpg123_store_utf8 T +mpg123_strerror T +mpg123_strlen T +mpg123_supported_decoders T +mpg123_tell T +mpg123_tell_64 T +mpg123_tell_stream T +mpg123_tell_stream_64 T +mpg123_tellframe T +mpg123_tellframe_64 T +mpg123_timeframe T +mpg123_timeframe_64 T +mpg123_tpf T +mpg123_volume T +mpg123_volume_change T diff --git a/ports/mpg123/port_rules.sh b/ports/mpg123/port_rules.sh new file mode 100755 index 0000000..ea58a04 --- /dev/null +++ b/ports/mpg123/port_rules.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +LINK=$1 +shift + +for LIST in $@ +do + grep '\.c$' ${LIST} | while read f + do + echo ": {port} |> !cc_port ${LINK}/${f} |> ${f}.o {obj}" + done + grep '\.S$' ${LIST} | while read f + do + echo ": {port} |> !cc_port ${LINK}/${f} |> ${f}.o {obj}" + done +done diff --git a/ports/mpg123/x86_64.files b/ports/mpg123/x86_64.files new file mode 100644 index 0000000..d10774b --- /dev/null +++ b/ports/mpg123/x86_64.files @@ -0,0 +1,5 @@ +src/libmpg123/getcpuflags_x86_64.S +src/libmpg123/dct64_x86_64.S +src/libmpg123/synth_stereo_x86_64.S +src/libmpg123/synth_x86_64.S +src/libmpg123/dct36_x86_64.S diff --git a/src/mp3_audio_sink/Tupfile b/src/mp3_audio_sink/Tupfile new file mode 100644 index 0000000..ee0569f --- /dev/null +++ b/src/mp3_audio_sink/Tupfile @@ -0,0 +1,12 @@ +TARGET_NAME = mp3_audio_sink +LIBS += mpg123 libc libm genode-gems + +include_rules + +INCLUDES += -I../cached_fs_rom + +: foreach *.cc |> !cxx |> %B.o {obj} +: {obj} | |> !prg |> {bin} +: {bin} |> !collect_bin |> + +include &(BIN_RULES) diff --git a/src/mp3_audio_sink/component.cc b/src/mp3_audio_sink/component.cc new file mode 100644 index 0000000..f089e41 --- /dev/null +++ b/src/mp3_audio_sink/component.cc @@ -0,0 +1,352 @@ +/* + * \brief MP3 audio decoder + * \author Emery Hemingway + * \date 2018-03-24 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* + * TODO: + * - Metadata report + * - Configure the mpg123 volume control and equalizer + * - Optimize buffer sizes + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Mpg123 includes */ +#include +#include +#include + +namespace Mp3_audio_sink { + + enum { LEFT, RIGHT, NUM_CHANNELS }; + + enum { + FEED_POOL_SIZE = 2, + CLIENT_BUFFER_SIZE = 1 << 14, /* 16 KiB */ + }; + + enum { + AUDIO_OUT_BUFFER_SIZE = NUM_CHANNELS + * Audio_out::QUEUE_SIZE + * Audio_out::PERIOD + * Audio_out::SAMPLE_SIZE + }; + + using namespace Genode; + + struct Decoder; + + class Terminal_component; + struct Main; +} + + +struct Mp3_audio_sink::Decoder +{ + template + static void for_each_channel(FUNC const &func) { + for (int i = 0; i < NUM_CHANNELS; ++i) func(i); } + + Genode::Env &_env; + + Attached_rom_dataspace _config_rom { _env, "config" }; + + Audio_out::Connection _out_left { _env, "left", true, true }; + Audio_out::Connection _out_right { _env, "right", false, false }; + Audio_out::Connection *_out[NUM_CHANNELS]; + + void die_mpg123(mpg123_handle *mh, char const *msg) + { + int code = mpg123_errcode(mh); + Genode::error(msg, ", ", mpg123_strerror(mh)); + + mpg123_close(mh); + mpg123_delete(mh); + mpg123_exit(); + + _env.parent().exit(code); + Genode::sleep_forever(); + } + + mpg123_handle *create_mpg123_handle() + { + mpg123_handle *mh = NULL; + + int err = mpg123_init(); + if(err != MPG123_OK || (mh = mpg123_new(NULL, &err)) == NULL) + Genode::error("Mpg123 setup failed, ", mpg123_plain_strerror(err)); + + mpg123_param(mh, MPG123_FEEDPOOL, FEED_POOL_SIZE, 0); + mpg123_param(mh, MPG123_FEEDBUFFER, CLIENT_BUFFER_SIZE, 0); + + /* Set mpg123 output format to match Audio_out exactly */ + mpg123_param(mh, MPG123_FORCE_RATE, + Audio_out::SAMPLE_RATE, Audio_out::SAMPLE_RATE); + mpg123_format_none(mh); + if (mpg123_format(mh, Audio_out::SAMPLE_RATE, + MPG123_STEREO, MPG123_ENC_FLOAT_32) != MPG123_OK) + die_mpg123(mh, "Audio_out format is unsupported"); + + if (mpg123_open_feed(mh) != MPG123_OK) + die_mpg123(mh, "mpg123 feeder mode failed"); + return mh; + } + + mpg123_handle *_mh = create_mpg123_handle(); + + /* last error code logged */ + int _mh_err = MPG123_OK; + + /** + * Use half of the available RAM as buffer + */ + size_t _pcm_buffer_size() + { + size_t n = _env.pd().avail_ram().value / 2; + if (n > (1<<20)) + log("internal buffer size is ", n>>20, "MiB"); + else if (n > (1<<10)) + log("internal buffer size is ", n>>10, "KiB"); + else + log("internal buffer size is ", n, " bytes"); + return n; + } + + Magic_ring_buffer _pcm { _env, _pcm_buffer_size() }; + + void _log_error() + { + int code = mpg123_errcode(_mh); + if (code != MPG123_OK && _mh_err != code) { + _mh_err = code; + error(mpg123_plain_strerror(code)); + } + } + + Genode::size_t feedbuffer_size() + { + long value = 0; + double fvalue = 0; + if (mpg123_getparam(_mh, MPG123_FEEDBUFFER, &value, &fvalue)) + die_mpg123(_mh, "failed to get feed buffer size"); + return value; + } + + void submit_audio(); + + /** + * Process client data, blocks until all data is consumed. + */ + void process(unsigned char const *src, size_t num_bytes) + { + /* TODO: patch mpgg123 not to use stdio for printing errors */ + + Libc::with_libc([&] () { + + /* feed client data into mpg123 buffer */ + if (mpg123_feed(_mh, src, num_bytes)) + die_mpg123(_mh, "failed to feed"); + + ::off_t num = 0; + unsigned char *audio = nullptr; + size_t bytes = 0; + + while (mpg123_decode_frame(_mh, &num, &audio, &bytes) == MPG123_OK) { + Genode::size_t const samples = bytes / Audio_out::SAMPLE_SIZE; + + while (_pcm.write_avail() < samples) { + /* submit audio blocks for packet allocation */ + submit_audio(); + } + + Genode::memcpy(_pcm.write_addr(), audio, bytes); + _pcm.fill(samples); + + } + + if (mpg123_errcode(_mh) != MPG123_ERR_READER + || mpg123_errcode(_mh) != MPG123_OK) + _log_error(); + }); + } + + Io_signal_handler _progress_handler { + _env.ep(), *this, &Decoder::submit_audio }; + + Signal_handler _config_handler { + _env.ep(), *this, &Decoder::_handle_config }; + + void _handle_config() + { + _config_rom.update(); + Xml_node const config = _config_rom.xml(); + + enum { EQ_COUNT = 32 }; + + mpg123_reset_eq(_mh); + config.for_each_sub_node("eq", [&] (Xml_node const &node) { + unsigned band = node.attribute_value("band", 32U); + double value = node.attribute_value("value", 0.0); + if (band < EQ_COUNT && value != 0.0) { + mpg123_eq(_mh, MPG123_LR , band, value); + log("EQ ", band, ": ", mpg123_geteq(_mh, MPG123_LR , band)); + } + }); + + double volume = 0.5; + config.for_each_sub_node("volume", [&] (Xml_node const &node) { + volume = node.attribute_value("linear", volume); }); + mpg123_volume(_mh, 0.5); + } + + Decoder(Genode::Env &env) : _env(env) + { + _out[LEFT] = &_out_left; + _out[RIGHT] = &_out_right; + _out_left.progress_sigh(_progress_handler); + _config_rom.sigh(_config_handler); + _handle_config(); + } +}; + + +void Mp3_audio_sink::Decoder::submit_audio() +{ + using namespace Audio_out; + + enum { STEREO_PERIOD = Audio_out::PERIOD*NUM_CHANNELS }; + + if (_out_left.stream()->empty()) { + for_each_channel([&] (int const c) { + _out[c]->start(); }); + log("Audio_out streams started"); + } + + while (_pcm.read_avail() > STEREO_PERIOD) { + Audio_out::Packet *p[NUM_CHANNELS]; + + while (true) { + try { p[LEFT] = _out[LEFT]->stream()->alloc(); break; } + catch (Audio_out::Stream::Alloc_failed) { + _out[LEFT]->wait_for_alloc(); } + } + + unsigned const ppos = _out[LEFT]->stream()->packet_position(p[LEFT]); + p[RIGHT] = _out[RIGHT]->stream()->get(ppos); + + float const *content = _pcm.read_addr(); + + /* copy channel contents into sessions */ + for (unsigned i = 0; i < STEREO_PERIOD; i += NUM_CHANNELS) { + for_each_channel([&] (int const c) { + p[c]->content()[i/NUM_CHANNELS] = content[i+c]; }); + } + + for_each_channel([&] (int const c) { + _out[c]->submit(p[c]); }); + _pcm.drain(STEREO_PERIOD); + } + + if (_out_left.stream()->empty()) { + log("Audio_out queue underrun, stopping stream"); + for_each_channel([&] (int const c) { + _out[c]->stop(); }); + } +} + + +class Mp3_audio_sink::Terminal_component : + public Rpc_object +{ + private: + + Decoder &_decoder; + + Genode::Attached_ram_dataspace _io_buffer; + + public: + + Terminal_component(Genode::Env &env, Decoder &decoder) + : + _decoder(decoder), + _io_buffer(env.pd(), env.rm(), _decoder.feedbuffer_size()) + { } + + + /******************************** + ** Terminal session interface ** + ********************************/ + + Genode::Dataspace_capability _dataspace() { + return _io_buffer.cap(); } + + Size size() { return Size(0, 0); } + + bool avail() { return false; } + + Genode::size_t read(void *, Genode::size_t) { return 0; } + Genode::size_t _read(Genode::size_t dst_len) { return 0; } + + Genode::size_t write(void const *, Genode::size_t) { return 0; } + Genode::size_t _write(Genode::size_t num_bytes) + { + /* sanitize argument */ + num_bytes = Genode::min(num_bytes, _io_buffer.size()); + + /* copy to decoder */ + _decoder.process( + _io_buffer.local_addr(), num_bytes); + + return num_bytes; + } + + void connected_sigh(Genode::Signal_context_capability cap) { + Genode::Signal_transmitter(cap).submit(); } + + void read_avail_sigh(Genode::Signal_context_capability) { } + + void size_changed_sigh(Genode::Signal_context_capability) { } +}; + + +struct Mp3_audio_sink::Main +{ + Genode::Env &_env; + + Decoder _decoder { _env }; + + Terminal_component _terminal { _env, _decoder }; + + Static_root _terminal_root { + _env.ep().manage(_terminal) }; + + Main(Libc::Env &env) : _env(env) + { + env.parent().announce(env.ep().manage(_terminal_root)); + } +}; + + +/*************** + ** Component ** + ***************/ + +void Libc::Component::construct(Libc::Env &env) { + static Mp3_audio_sink::Main _main(env); }