diff --git a/repos/dde_bsd/recipes/src/bsd_audio_drv/used_apis b/repos/dde_bsd/recipes/src/bsd_audio_drv/used_apis
index d4828db7e1..8d1a0fe5d2 100644
--- a/repos/dde_bsd/recipes/src/bsd_audio_drv/used_apis
+++ b/repos/dde_bsd/recipes/src/bsd_audio_drv/used_apis
@@ -4,5 +4,7 @@ format
audio_in_session
audio_out_session
platform_session
+play_session
+record_session
report_session
timer_session
diff --git a/repos/dde_bsd/run/audio_in.run b/repos/dde_bsd/run/audio_in.run
index 182948f62d..a759c3d755 100644
--- a/repos/dde_bsd/run/audio_in.run
+++ b/repos/dde_bsd/run/audio_in.run
@@ -10,30 +10,71 @@ if {[have_spec linux]} {
exit 0
}
+# select use of 'Audio_in/Audio_out' or 'Record/Play' sessions
+proc use_record_play_sessions { } { return 1 }
-#
-# Build
-#
+proc build_targets { } {
-set build_components {
- core init timer
- drivers/acpi
- drivers/platform
- app/pci_decode
- server/report_rom
- drivers/audio
- test/audio_in
+ set targets {
+ core init timer
+ drivers/acpi drivers/platform app/pci_decode server/report_rom
+ drivers/audio
+ }
+
+ if {[use_record_play_sessions]} {
+ lappend targets server/record_play_mixer
+ } else {
+ lappend targets test/audio_in
+ }
}
-build $build_components
+build [build_targets]
create_boot_directory
-#
-# Config
-#
+proc audio_driver_config_attr { } {
-append config {
+ if {[use_record_play_sessions]} {
+ return {report_mixer="yes" record_play="yes"}
+ } else {
+ return {report_mixer="yes"}
+ }
+}
+
+proc record_play_start_nodes { } {
+
+ if {![use_record_play_sessions]} { return "" }
+
+ return {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+}
+
+proc audio_in_out_start_nodes { } {
+
+ if {[use_record_play_sessions]} { return "" }
+
+ return {
+
+
+
+ }
+}
+
+install_config {
@@ -67,12 +108,7 @@ append config {
-
-
-
-
-
-
+
@@ -81,12 +117,7 @@ append config {
-
-
-
-
-
-
+
@@ -98,13 +129,7 @@ append config {
-
-
-
-
-
-
-
+
@@ -118,31 +143,19 @@ append config {
-
+
-
-
-
+
+ } [record_play_start_nodes] {
+ } [audio_in_out_start_nodes] {
+
}
-install_config $config
-
-
-#
-# Boot modules
-#
-
-set boot_modules {
- core ld.lib.so init timer
- platform_drv acpi_drv pci_decode report_rom
- pci_audio_drv test-audio_in
-}
-
-build_boot_image $boot_modules
+build_boot_image [build_artifacts]
run_genode_until forever
diff --git a/repos/dde_bsd/run/audio_out.run b/repos/dde_bsd/run/audio_out.run
index def5a1f68d..17d48353bf 100644
--- a/repos/dde_bsd/run/audio_out.run
+++ b/repos/dde_bsd/run/audio_out.run
@@ -10,16 +10,87 @@ if {[have_spec linux]} {
exit 0
}
+# select use of 'Audio_in/Audio_out' or 'Record/Play' sessions
+proc use_record_play_sessions { } { return 1 }
create_boot_directory
-build {
- core init timer
- drivers/acpi
- drivers/platform
- app/pci_decode
- server/report_rom
- drivers/audio
- test/audio_out
+
+proc build_targets { } {
+
+ set targets {
+ core init timer
+ drivers/acpi drivers/platform app/pci_decode server/report_rom
+ drivers/audio
+ }
+
+ if {[use_record_play_sessions]} {
+ lappend targets server/record_play_mixer app/waveform_player \
+ test/audio_play lib/vfs
+ } else {
+ lappend targets test/audio_out
+ }
+}
+
+build [build_targets]
+
+proc audio_driver_config_attr { } {
+
+ if {[use_record_play_sessions]} {
+ return {report_mixer="yes" record_play="yes"}
+ } else {
+ return {report_mixer="yes"}
+ }
+}
+
+proc record_play_start_nodes { } {
+
+ if {![use_record_play_sessions]} {
+ return "" }
+
+ return {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+}
+
+proc audio_in_out_start_nodes { } {
+
+ if {[use_record_play_sessions]} {
+ return "" }
+
+ return {
+
+
+
+ sample.f32
+
+
+
+
+
+ }
}
install_config {
@@ -45,7 +116,7 @@ install_config {
-
+
@@ -55,12 +126,7 @@ install_config {
-
-
-
-
-
-
+
@@ -69,12 +135,7 @@ install_config {
-
-
-
-
-
-
+
@@ -86,13 +147,7 @@ install_config {
-
-
-
-
-
-
-
+
@@ -102,43 +157,28 @@ install_config {
-
-
+
+
-
-
-
- sample.raw
-
-
-
-
-
+ } [record_play_start_nodes] {
+ } [audio_in_out_start_nodes] {
+
}
#
# Get sample file
#
-if {![file exists bin/sample.raw]} {
+if {![file exists bin/sample.f32]} {
puts ""
puts "The sample file is missing. Please take a look at"
- puts "repos/dde_bsd/README, create 'sample.raw' and put"
+ puts "repos/dde_bsd/README, create 'sample.f32' and put"
puts "the file into './bin'. afterwards"
puts ""
exit 1
}
-build_boot_image {
- core ld.lib.so init timer
- platform_drv acpi_drv pci_decode report_rom
- pci_audio_drv test-audio_out sample.raw
-}
+build_boot_image [list {*}[build_artifacts] sample.f32]
-
-#
-# For obvious reasons the timeout depends on the total
-# length of the used sample file.
-#
-run_genode_until {.*played.*1 time\(s\)} 60
+run_genode_until forever
diff --git a/repos/dde_bsd/src/drivers/audio/main.cc b/repos/dde_bsd/src/drivers/audio/main.cc
index 7b0e72b62a..dc1dbeef49 100644
--- a/repos/dde_bsd/src/drivers/audio/main.cc
+++ b/repos/dde_bsd/src/drivers/audio/main.cc
@@ -15,6 +15,8 @@
/* Genode includes */
#include
#include
+#include
+#include
#include
#include
#include
@@ -467,6 +469,144 @@ class Audio_in::Root : public Audio_in::Root_component
};
+struct Stereo_output : Noncopyable
+{
+ static constexpr unsigned SAMPLES_PER_PERIOD = Audio_in::PERIOD;
+ static constexpr unsigned CHANNELS = 2;
+
+ Env &_env;
+
+ Record::Connection _left { _env, "left" };
+ Record::Connection _right { _env, "right" };
+
+ struct Recording : private Noncopyable
+ {
+ bool depleted = false;
+
+ /* 16 bit per sample, interleaved left and right */
+ int16_t data[SAMPLES_PER_PERIOD*CHANNELS] { };
+
+ void clear() { for (auto &e : data) e = 0; }
+
+ void from_record_sessions(Record::Connection &left, Record::Connection &right)
+ {
+ using Samples_ptr = Record::Connection::Samples_ptr;
+
+ bool const orig_depleted = depleted;
+
+ Record::Num_samples const num_samples { SAMPLES_PER_PERIOD };
+
+ auto clamped = [&] (float v)
+ {
+ return (v > 1.0) ? 1.0
+ : (v < -1.0) ? -1.0
+ : v;
+ };
+
+ auto float_to_s16 = [&] (float v) { return int16_t(clamped(v)*32767); };
+
+ left.record(num_samples,
+ [&] (Record::Time_window const tw, Samples_ptr const &samples) {
+ depleted = false;
+
+ for (unsigned i = 0; i < SAMPLES_PER_PERIOD; i++)
+ data[i*CHANNELS] = float_to_s16(samples.start[i]);
+
+ right.record_at(tw, num_samples,
+ [&] (Samples_ptr const &samples) {
+ for (unsigned i = 0; i < SAMPLES_PER_PERIOD; i++)
+ data[i*CHANNELS + 1] = float_to_s16(samples.start[i]);
+ });
+ },
+ [&] {
+ depleted = true;
+ clear();
+ }
+ );
+
+ if (orig_depleted != depleted && depleted)
+ log("recording depleted");
+ }
+ };
+
+ Recording _recording { };
+
+ Signal_handler _output_handler {
+ _env.ep(), *this, &Stereo_output::_handle_output };
+
+ void _handle_output()
+ {
+ _recording.from_record_sessions(_left, _right);
+ Audio::play(_recording.data, sizeof(_recording.data));
+ }
+
+ Stereo_output(Env &env) : _env(env)
+ {
+ Audio::play_sigh(_output_handler);
+
+ /* submit two silent packets to get the driver going */
+ Audio::play(_recording.data, sizeof(_recording.data));
+ Audio::play(_recording.data, sizeof(_recording.data));
+ }
+};
+
+
+struct Stereo_input : Noncopyable
+{
+ static constexpr unsigned SAMPLES_PER_PERIOD = Audio_in::PERIOD;
+ static constexpr unsigned CHANNELS = 2;
+
+ Env &_env;
+
+ Play::Connection _left { _env, "left" };
+ Play::Connection _right { _env, "right" };
+
+ /* 16 bit per sample, interleaved left and right */
+ int16_t data[SAMPLES_PER_PERIOD*CHANNELS] { };
+
+ struct Frame { float left, right; };
+
+ void _for_each_frame(auto const &fn) const
+ {
+ float const scale = 1.0f/32768;
+
+ for (unsigned i = 0; i < SAMPLES_PER_PERIOD; i++)
+ fn(Frame { .left = scale*float(data[i*CHANNELS]),
+ .right = scale*float(data[i*CHANNELS + 1]) });
+ }
+
+ Play::Time_window _time_window { };
+
+ Signal_handler _input_handler {
+ _env.ep(), *this, &Stereo_input::_handle_input };
+
+ void _handle_input()
+ {
+ if (int const err = Audio::record(data, sizeof(data))) {
+ if (err && err != 35)
+ warning("error ", err, " during recording");
+ return;
+ }
+
+ Play::Duration const duration_us { 11*1000 }; /* hint for first period */
+ _time_window = _left.schedule_and_enqueue(_time_window, duration_us,
+ [&] (auto &submit) {
+ _for_each_frame([&] (Frame const frame) {
+ submit(frame.left); }); });
+
+ _right.enqueue(_time_window,
+ [&] (auto &submit) {
+ _for_each_frame([&] (Frame const frame) {
+ submit(frame.right); }); });
+ }
+
+ Stereo_input(Env &env) : _env(env)
+ {
+ Audio::record_sigh(_input_handler);
+ }
+};
+
+
/**********
** Main **
**********/
@@ -487,17 +627,30 @@ struct Main
Audio::update_config(_env, _config.xml());
}
+ bool const _record_play = _config.xml().attribute_value("record_play", false);
+
Constructible _out { };
Constructible _out_root { };
Constructible _in { };
Constructible _in_root { };
+ Constructible _stereo_output { };
+ Constructible _stereo_input { };
+
Signal_handler _announce_session_handler {
_env.ep(), *this, &Main::_handle_announce_session };
void _handle_announce_session()
{
+ if (_record_play) {
+ _stereo_output.construct(_env);
+ _stereo_input .construct(_env);
+ return;
+ }
+
+ /* Audio_out/Audio_in mode */
+
_out.construct(_env);
Audio::play_sigh(_out->sigh());