diff --git a/repos/os/recipes/pkg/black_hole/runtime b/repos/os/recipes/pkg/black_hole/runtime index 813a43eb41..e542d2d78e 100644 --- a/repos/os/recipes/pkg/black_hole/runtime +++ b/repos/os/recipes/pkg/black_hole/runtime @@ -1,11 +1,15 @@ + + + + diff --git a/repos/os/recipes/src/black_hole/used_apis b/repos/os/recipes/src/black_hole/used_apis index 56a415c335..62eaff0596 100644 --- a/repos/os/recipes/src/black_hole/used_apis +++ b/repos/os/recipes/src/black_hole/used_apis @@ -1,2 +1,5 @@ base +audio_in_session audio_out_session +capture_session +os diff --git a/repos/os/src/server/black_hole/README b/repos/os/src/server/black_hole/README index 4eff4fc987..eab164909c 100644 --- a/repos/os/src/server/black_hole/README +++ b/repos/os/src/server/black_hole/README @@ -1,9 +1,15 @@ The 'black_hole' component provides dummy implementations of common session interfaces. -At this time, only the 'Audio_out' session is provided if enabled +At this time, the following sessions are provided if enabled in the configuration of the component: +* Audio_in +* Audio_out +* Capture + + + diff --git a/repos/os/src/server/black_hole/audio_in.h b/repos/os/src/server/black_hole/audio_in.h new file mode 100644 index 0000000000..d9070036dd --- /dev/null +++ b/repos/os/src/server/black_hole/audio_in.h @@ -0,0 +1,159 @@ +/* + * \brief 'Audio_in' part of black hole component + * \author Christian Prochaska + * \date 2021-07-07 + * + */ + +/* + * Copyright (C) 2021-2022 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. + */ + +#ifndef _AUDIO_IN_H_ +#define _AUDIO_IN_H_ + +/* Genode includes */ +#include +#include + + +namespace Audio_in +{ + class Session_component_base; + class Session_component; + class Root; +} + + +/** + * This base struct is needed to get the 'Signal_handler' constructed + * before the 'Session_rpc_object' constructor is called with the handler + * as argument. + */ + +struct Audio_in::Session_component_base +{ + Genode::Signal_handler _data_available_handler; + Timer::One_shot_timeout _timeout; + + virtual void _handle_data_available() = 0; + virtual void _handle_timeout(Genode::Duration) = 0; + + Session_component_base(Genode::Env &env, Timer::Connection &timer) + : _data_available_handler(env.ep(), + *this, + &Session_component_base::_handle_data_available), + _timeout(timer, *this, &Session_component_base::_handle_timeout) + { } + + virtual ~Session_component_base() { } +}; + + +class Audio_in::Session_component : Audio_in::Session_component_base, + public Audio_in::Session_rpc_object +{ + private: + + Genode::Microseconds _delay { + (Audio_in::PERIOD * 1000 * 1000) / Audio_in::SAMPLE_RATE }; + + void _handle_data_available() override + { + _timeout.schedule(_delay); + } + + void _handle_timeout(Genode::Duration) override + { + if (!active()) + return; + + Packet *p = stream()->alloc(); + + Genode::memset(p->content(), 0, + Audio_in::PERIOD * Audio_in::SAMPLE_SIZE); + + stream()->submit(p); + + progress_submit(); + + _timeout.schedule(_delay); + } + + public: + + Session_component(Genode::Env &env, Timer::Connection &timer) + : Session_component_base(env, timer), + Session_rpc_object(env, _data_available_handler) + { } + + ~Session_component() + { + if (Session_rpc_object::active()) stop(); + } + + void start() override + { + Session_rpc_object::start(); + _timeout.schedule(_delay); + } + + void stop() override + { + Session_rpc_object::stop(); + } +}; + + +namespace Audio_in { + typedef Genode::Root_component Root_component; +} + + +class Audio_in::Root : public Audio_in::Root_component +{ + private: + + Genode::Env &_env; + Timer::Connection _timer; + + Session_component *_create_session(const char *args) override + { + using namespace Genode; + + size_t ram_quota = + Arg_string::find_arg(args, "ram_quota").ulong_value(0); + + size_t session_size = align_addr(sizeof(Session_component), 12); + + if ((ram_quota < session_size) || + (sizeof(Stream) > ram_quota - session_size)) { + Genode::error("insufficient 'ram_quota', got ", ram_quota, ", " + "need ", sizeof(Stream) + session_size); + throw Insufficient_ram_quota(); + } + + Session_component *session = new (md_alloc()) + Session_component(_env, _timer); + + return session; + + } + + void _destroy_session(Session_component *session) override + { + Genode::destroy(md_alloc(), session); + } + + public: + + Root(Genode::Env &env, + Genode::Allocator &md_alloc) + : Root_component(env.ep(), md_alloc), + _env(env), _timer(env) { } +}; + +#endif /* _AUDIO_IN_H_ */ diff --git a/repos/os/src/server/black_hole/capture.h b/repos/os/src/server/black_hole/capture.h new file mode 100644 index 0000000000..598c24d467 --- /dev/null +++ b/repos/os/src/server/black_hole/capture.h @@ -0,0 +1,150 @@ +/* + * \brief 'Capture' part of black hole component + * \author Christian Prochaska + * \date 2021-09-24 + * + */ + +/* + * Copyright (C) 2021-2022 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. + */ + +#ifndef _CAPTURE_H_ +#define _CAPTURE_H_ + +/* Genode includes */ +#include +#include + +#include +#include + + +namespace Capture +{ + using namespace Genode; + class Session_component; + class Root; +} + + +class Capture::Session_component : public Session_object +{ + private: + + Env &_env; + + Constrained_ram_allocator _ram; + + Constructible _buffer { }; + + public: + + Session_component(Env &env, + Resources const &resources, + Label const &label, + Diag const &diag) + : + Session_object(env.ep(), resources, label, diag), + _env(env), + _ram(env.ram(), _ram_quota_guard(), _cap_quota_guard()) + { } + + ~Session_component() { } + + + /******************************* + ** Capture session interface ** + *******************************/ + + Area screen_size() const override + { + return Area(640, 480); + } + + void screen_size_sigh(Signal_context_capability) override { } + + void buffer(Area size) override + { + if (size.count() == 0) { + _buffer.destruct(); + return; + } + + _buffer.construct(_ram, _env.rm(), buffer_bytes(size)); + } + + Dataspace_capability dataspace() override + { + if (_buffer.constructed()) + return _buffer->cap(); + + return Dataspace_capability(); + } + + Affected_rects capture_at(Point) override + { + return Affected_rects(); + } +}; + + +namespace Capture { + typedef Genode::Root_component Root_component; +} + + +class Capture::Root : public Capture::Root_component +{ + private: + + Genode::Env &_env; + + Session_component *_create_session(const char *args) override + { + using namespace Genode; + + size_t ram_quota = + Arg_string::find_arg(args, "ram_quota").ulong_value(0); + + size_t session_size = align_addr(sizeof(Session_component), 12); + + if ((ram_quota < session_size)) { + Genode::error("insufficient 'ram_quota', got ", ram_quota, ", " + "need ", session_size); + throw Insufficient_ram_quota(); + } + + Session_component *session = new (md_alloc()) + Session_component(_env, + session_resources_from_args(args), + session_label_from_args(args), + session_diag_from_args(args)); + + return session; + + } + + void _upgrade_session(Session_component *s, const char *args) override + { + s->upgrade(ram_quota_from_args(args)); + s->upgrade(cap_quota_from_args(args)); + } + + void _destroy_session(Session_component *session) override + { + Genode::destroy(md_alloc(), session); + } + + public: + + Root(Genode::Env &env, + Genode::Allocator &md_alloc) + : Root_component(env.ep(), md_alloc), + _env(env) { } +}; + +#endif /* _CAPTURE_H_ */ diff --git a/repos/os/src/server/black_hole/main.cc b/repos/os/src/server/black_hole/main.cc index 0a33c5b442..9f24169094 100644 --- a/repos/os/src/server/black_hole/main.cc +++ b/repos/os/src/server/black_hole/main.cc @@ -21,7 +21,9 @@ #include /* local includes */ +#include "audio_in.h" #include "audio_out.h" +#include "capture.h" /*************** @@ -36,16 +38,28 @@ struct Black_hole::Main Genode::Sliced_heap heap { env.ram(), env.rm() }; + Genode::Constructible audio_in_root { }; Genode::Constructible audio_out_root { }; + Genode::Constructible capture_root { }; Main(Genode::Env &env) : env(env) { Genode::Attached_rom_dataspace _config_rom { env, "config" }; + if (_config_rom.xml().has_sub_node("audio_in")) { + audio_in_root.construct(env, heap); + env.parent().announce(env.ep().manage(*audio_in_root)); + } + if (_config_rom.xml().has_sub_node("audio_out")) { audio_out_root.construct(env, heap); env.parent().announce(env.ep().manage(*audio_out_root)); } + + if (_config_rom.xml().has_sub_node("capture")) { + capture_root.construct(env, heap); + env.parent().announce(env.ep().manage(*capture_root)); + } } };