Compare commits

...

4 Commits
audio ... solo5

Author SHA1 Message Date
Ehmry - 724197a973 !drop 2019-07-09 13:26:16 +02:00
Ehmry - bc53f5cb8c Compile PIC by default 2019-07-09 13:26:01 +02:00
Ehmry - 51eeb3cec7 !drop 2019-07-09 13:25:47 +02:00
Ehmry - 8e5510d5e3 mp3_audio_sink 2019-07-09 13:25:20 +02:00
24 changed files with 818 additions and 15 deletions

3
.gitmodules vendored
View File

@ -106,3 +106,6 @@
[submodule "libretro/cores/yabause/upstream"]
path = libretro/cores/yabause/upstream
url = https://github.com/libretro/yabause.git
[submodule "solo5/upstream"]
path = solo5/upstream
url = https://github.com/Solo5/solo5.git

View File

@ -161,13 +161,13 @@ PKG_CONFIG = PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) pkg-config
!asm = |> ^ CC %b^ @(CC_WRAPPER) $(CC) $(DEFINES) $(CFLAGS) $(CFLAGS_%e) $(CFLAGS_%f) -D__ASSEMBLY__ $(INCLUDES) -c %f -o %o |> %B.o
!cc = | $(GENODE_DIR)/<pkg-config> |> ^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 = | $(GENODE_DIR)/<pkg-config> |> ^o CC %f^ @(CC_WRAPPER) $(CC) $(DEFINES) $(CFLAGS) $(CFLAGS_%e) $(CFLAGS_%f) `$(PKG_CONFIG) --cflags $(LIBS) $(LIBS_CFLAGS)` $(INCLUDES) -c -fPIC %f -o %o |> %B.o
!cc_port = | $(GENODE_DIR)/<pkg-config> |> ^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)/<pkg-config> |> ^o CC %o^ @(CC_WRAPPER) $(CC) $(DEFINES) $(CFLAGS) $(CFLAGS_%o) $(INCLUDES) `$(PKG_CONFIG) --cflags $(LIBS) $(LIBS_CFLAGS)` -c -fPIC -o %o |> %B.o
!cxx = | $(GENODE_DIR)/<pkg-config> |> ^o CXX %b^ @(CC_WRAPPER) $(CXX) $(DEFINES) $(CXXFLAGS) $(CXXFLAGS_%e) $(CXXFLAGS_%f) `$(PKG_CONFIG) --cflags $(LIBS)` $(INCLUDES) -c %f -o %o |> %B.o
!cxx = | $(GENODE_DIR)/<pkg-config> |> ^o CXX %b^ @(CC_WRAPPER) $(CXX) $(DEFINES) $(CXXFLAGS) $(CXXFLAGS_%e) $(CXXFLAGS_%f) `$(PKG_CONFIG) --cflags $(LIBS)` $(INCLUDES) -c -fPIC %f -o %o |> %B.o
!cxx_port = | $(GENODE_DIR)/<pkg-config> |> ^o CXX %o^ @(CC_WRAPPER) $(CXX) -c $(DEFINES) $(CXXFLAGS) $(CXXFLAGS_%f) `$(PKG_CONFIG) --cflags $(LIBS)` $(INCLUDES) -o %o |> %B.o
!cxx_port = | $(GENODE_DIR)/<pkg-config> |> ^o CXX %o^ @(CC_WRAPPER) $(CXX) $(DEFINES) $(CXXFLAGS) $(CXXFLAGS_%f) `$(PKG_CONFIG) --cflags $(LIBS)` $(INCLUDES) -c -fPIC -o %o |> %B.o
!ld = | $(GENODE_DIR)/<lib> $(GENODE_DIR)/<pkg-config> |> ^o LD %o^ $(LD) $(LDFLAGS) `$(PKG_CONFIG) --libs $(LIBS)` %f -o %o |>

View File

@ -19,6 +19,7 @@
<xs:element name="log" type="template_service"/>
<xs:element name="nic" type="template_service"/>
<xs:element name="nitpicker" type="template_service"/>
<xs:element name="platform" type="template_service"/>
<xs:element name="report" type="template_service"/>
<xs:element name="rm" type="template_service"/>
<xs:element name="rom" type="template_service"/>

View File

@ -1,5 +1,16 @@
<index>
<index name="Audio">
<pkg path="_/pkg/mixer" info="Mixer component"/>
<pkg path="_/pkg/bsd_audio_drv" info="OpenBSD audio driver (mixer client)"/>
<pkg path="ehmry/pkg/audio_player/2019-05-24" info="Cnuke's audio player"/>
<index name="Radio streams">
<pkg path="_/pkg/ifm1" info="Intergalactic FM 1"/>
<pkg path="_/pkg/ifm2" info="Intergalactic FM 2"/>
<pkg path="_/pkg/ifm3" info="Intergalactic FM 3"/>
</index>
</index>
<index name="Emulators and game engines">
<pkg path="_/pkg/dosbox" info="Experimental Libretro port of DOSBox"/>
<pkg path="_/pkg/fceumm" info="NES"/>
@ -60,10 +71,6 @@
</index>
<index name="Utility">
<index name="Audio">
<pkg path="ehmry/pkg/bsd_audio_drv/2019-05-24" info="Cnuke's audio driver"/>
<pkg path="ehmry/pkg/audio_player/2019-05-24" info="Cnuke's audio player"/>
</index>
<index name="Graphic">
<!-- <pkg path="ehmry/pkg/flif_capture/2019-03-22" info="Screen capture utility"/> -->
@ -100,12 +107,6 @@
</index>
</index>
<index name="Radio streams">
<pkg path="_/pkg/ifm1" info="Intergalactic FM 1"/>
<pkg path="_/pkg/ifm2" info="Intergalactic FM 2"/>
<pkg path="_/pkg/ifm3" info="Intergalactic FM 3"/>
</index>
<index name="Experimental">
<index name="Semantic audio player demo">
<pkg path="_/pkg/blob_service" info="Blobsets package with file-system and HTTP frontends"/>

View File

@ -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 (

35
ports/mpg123/Tupfile Normal file
View File

@ -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)/<pkg-config>
: 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)

1
ports/mpg123/arm.files Normal file
View File

@ -0,0 +1 @@
src/libmpg123/synth_arm.S

38
ports/mpg123/common.files Normal file
View File

@ -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

48
ports/mpg123/config.h Normal file
View File

@ -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

27
ports/mpg123/default.nix Normal file
View File

@ -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
'';
}

115
ports/mpg123/mpg123.symbols Normal file
View File

@ -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

16
ports/mpg123/port_rules.sh Executable file
View File

@ -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

View File

@ -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

32
solo5/Tupfile Normal file
View File

@ -0,0 +1,32 @@
TARGET_NAME = solo5
LIBS += genode-os
include_rules
: solo5.symbols |> !abi_stub |>
: solo5.pc.in |> ^ SED %B^ \
sed \
-e "s|@includedir@|`nix-store --add upstream/include`|" \
-e "s|@version@|`git describe`|" \
< %f > %o \
|> $(PKG_CONFIG_DIR)/solo5.pc $(GENODE_DIR)/<pkg-config>
: |> cc -Iupstream/include/solo5 upstream/%o/%o.c -o %o |> mfttool
DEFINES += -D__SOLO5_BINDINGS__
CXXFLAGS += -Drestrict=__restrict__
DEFINES += -Wno-builtin-declaration-mismatch
INCLUDES += -Iupstream/include/solo5
INCLUDES += -Iupstream/include/crt
#: foreach ../../tenders/common/mft.c |> !cc |> {obj}
BINDINGS_DIR = upstream/bindings/genode
: foreach $(BINDINGS_DIR)/*.cc |> !cxx |> {obj}
: {obj} |> !lib |> solo5.lib.so {bin}
: {bin} |> !collect_bin |>
include &(BIN_RULES)

3
solo5/Tuprules.tup Normal file
View File

@ -0,0 +1,3 @@
DEFINES += -fstack-protector-strong
DEFINES += -Wno-builtin-declaration-mismatch
INCLUDES += -I$(TUP_CWD)

7
solo5/solo5.pc.in Normal file
View File

@ -0,0 +1,7 @@
includedir=@includedir@
Name: solo5
Version: @version@
Description: Solo5 sandboxed execution environment
Cflags: -I${includedir}/crt -I${includedir}/solo5
Libs: -l:solo5.lib.so

17
solo5/solo5.symbols Normal file
View File

@ -0,0 +1,17 @@
__solo5_manifest_note U
solo5_app_main U
solo5_abort T
solo5_block_acquire T
solo5_block_info T
solo5_block_read T
solo5_block_write T
solo5_clock_monotonic T
solo5_clock_wall T
solo5_console_write T
solo5_exit T
solo5_net_acquire T
solo5_net_info T
solo5_net_read T
solo5_net_write T
solo5_set_tls_base T
solo5_yield T

12
solo5/stdint.h Normal file
View File

@ -0,0 +1,12 @@
// Genode stdint.h
#include <base/fixed_stdint.h>
typedef genode_int8_t int8_t;
typedef genode_uint8_t uint8_t;
typedef genode_int16_t int16_t;
typedef genode_uint16_t uint16_t;
typedef genode_int32_t int32_t;
typedef genode_uint32_t uint32_t;
typedef genode_int64_t int64_t;
typedef genode_uint64_t uint64_t;
typedef unsigned long uintptr_t;

33
solo5/test/Tupfile Normal file
View File

@ -0,0 +1,33 @@
TARGET_NAME = solo5_tests
LIBS += solo5 genode-base
include_rules
PKG_DEPENDS += \
_/src/init \
_/src/nic_bus \
_/src/ram_block \
_/src/sequence \
_/src/solo5 \
_/src/$(BIN_NAME) \
run ./test_rules.sh \
blk \
dumpcore \
exception \
fpu \
globals \
hello \
net \
net_2if \
notls \
quiet \
ssp \
time \
wnox \
xnow \
: foreach {bin} |> !collect_bin |>
: runtime |> !collect_pkg_runtime |>
include &(BIN_RULES)
include &(PKG_RULES)

72
solo5/test/runtime Normal file
View File

@ -0,0 +1,72 @@
<runtime ram="32M" caps="1000" binary="init">
<!--
<events>
<timeout meaning="failed" sec="60" />
<log meaning="succeeded">
[init] child "test" exited with exit value 0
</log>
<log meaning="failed">Error: </log>
</events>
-->
<requires> <rtc/> </requires>
<content>
<rom label="ram_block"/>
<rom label="sequence"/>
<rom label="solo5.lib.so"/>
<rom label="test_blk"/>
<rom label="test_exception"/>
<rom label="test_fpu"/>
<rom label="test_globals"/>
<rom label="test_hello"/>
<rom label="test_net"/>
<rom label="test_net_2if"/>
<rom label="test_notls"/>
<rom label="test_quiet"/>
<rom label="test_ssp"/>
<rom label="test_time"/>
<rom label="test_wnox"/>
<rom label="test_xnow"/>
</content>
<config>
<parent-provides>
<service name="CPU"/>
<service name="LOG"/>
<service name="PD"/>
<service name="RM"/>
<service name="ROM"/>
<service name="Rtc"/>
<service name="Timer"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<start name="ram_block" caps="96">
<resource name="RAM" quantum="9M"/>
<provides> <service name="Block"/> </provides>
<config size="8M" block_size="4096"/>
</start>
<start name="test" caps="256">
<binary name="sequence"/>
<resource name="RAM" quantum="16M"/>
<config ld_verbose="yes">
<start name="test_hello">
<config>
<cmdline>Hello_Solo5</cmdline>
</config>
</start>
<start name="test_blk"/>
<start name="test_exception"/>
<start name="test_fpu"/>
<start name="test_globals"/>
<start name="test_quiet"/>
<start name="test_ssp"/>
<start name="test_time"/>
</config>
</start>
</config>
</runtime>

8
solo5/test/test_rules.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
for T in ${@}
do
echo ": ../mfttool |> %f gen ../upstream/tests/test_${T}/manifest.json %o |> ${T}_manifest.c {${T}-manifest}"
echo ": foreach {${T}-manifest} ../upstream/tests/test_${T}/*.c |> !cc |> %B.o {${T}-obj}"
echo ": {${T}-obj} |> !prg |> test_${T} {bin}"
done

1
solo5/upstream Submodule

@ -0,0 +1 @@
Subproject commit 0a43c262df2df0839a1d1a93228b38842db4154c

View File

@ -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)

View File

@ -0,0 +1,317 @@
/*
* \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
* - Optimize buffer sizes
*/
/* Genode includes */
#include <gems/magic_ring_buffer.h>
#include <os/static_root.h>
#include <libc/component.h>
#include <audio/source.h>
#include <terminal_session/connection.h>
#include <base/attached_rom_dataspace.h>
#include <base/attached_ram_dataspace.h>
#include <base/sleep.h>
/* Mpg123 includes */
#include <stdlib.h>
#include <sys/types.h>
#include <mpg123.h>
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 : Audio::Source
{
template <typename FUNC>
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::Stereo_out _stereo_out { _env, *this };
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<float> _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;
}
bool fill(float *left, float *right, Genode::size_t samples) override;
/**
* 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 */
_env.ep().wait_and_dispatch_one_io_signal();
}
Genode::memcpy(_pcm.write_addr(), audio, bytes);
_pcm.fill(samples);
}
if (mpg123_errcode(_mh) != MPG123_ERR_READER
|| mpg123_errcode(_mh) != MPG123_OK)
_log_error();
});
}
Signal_handler<Decoder> _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)
{
_config_rom.sigh(_config_handler);
_handle_config();
}
};
bool Mp3_audio_sink::Decoder::fill(float *left,
float *right,
Genode::size_t samples)
{
using namespace Audio_out;
if (_pcm.read_avail() < samples*2) return false;
float const *buf = _pcm.read_addr();
for (unsigned i = 0; i < samples; ++i) {
left[i] = buf[(i<<1)|0];
right[i] = buf[(i<<1)|1];
}
_pcm.drain(samples*2);
return true;
}
class Mp3_audio_sink::Terminal_component :
public Rpc_object<Terminal::Session, Terminal_component>
{
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<unsigned char>(), 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::Session> _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); }