vfs_oss: implement 'SNDCTL_DSP_SETTRIGGER' command

Fixes #4579
This commit is contained in:
Christian Prochaska 2022-07-27 10:58:11 +02:00 committed by Christian Helmuth
parent a4ec06a3b7
commit bda276f498
3 changed files with 129 additions and 10 deletions

View File

@ -1682,7 +1682,41 @@ Libc::Vfs_plugin::_ioctl_sndctl(File_descriptor *fd, unsigned long request, char
if (!argp) return { true, EINVAL };
/* dummy implementation */
int mask = *(int *)argp;
if (((fd->flags & O_ACCMODE) == O_RDONLY) ||
((fd->flags & O_ACCMODE) == O_RDWR)) {
char enable_input_string[2];
::snprintf(enable_input_string, sizeof(enable_input_string),
"%u", (mask & PCM_ENABLE_INPUT) ? 1 : 0);
Absolute_path enable_input_path = ioctl_dir(*fd);
enable_input_path.append_element("enable_input");
File_descriptor *enable_input_fd = open(enable_input_path.base(), O_WRONLY);
if (!enable_input_fd)
return { true, ENOTSUP };
write(enable_input_fd, enable_input_string, sizeof(enable_input_string));
close(enable_input_fd);
}
if (((fd->flags & O_ACCMODE) == O_WRONLY) ||
((fd->flags & O_ACCMODE) == O_RDWR)) {
char enable_output_string[2];
::snprintf(enable_output_string, sizeof(enable_output_string),
"%u", (mask & PCM_ENABLE_OUTPUT) ? 1 : 0);
Absolute_path enable_output_path = ioctl_dir(*fd);
enable_output_path.append_element("enable_output");
File_descriptor *enable_output_fd = open(enable_output_path.base(), O_WRONLY);
if (!enable_output_fd)
return { true, ENOTSUP };
write(enable_output_fd, enable_output_string, sizeof(enable_output_string));
close(enable_output_fd);
}
handled = true;

View File

@ -71,6 +71,14 @@ presents all files:
* halt_output (wo): writing anything into this file halts output processing.
Corresponding OSS commands: SNDCTL_DSP_HALT
* enable_input (rw): writing 1 or 0 into this file enables or disables
input processing.
Corresponding OSS commands: SNDCTL_DSP_SETTRIGGER
* enable_output (rw): writing 1 or 0 into this file enables or disables
output processing.
Corresponding OSS commands: SNDCTL_DSP_SETTRIGGER
In its current state the plugin is merely enough to use simple applications requiring
nothing more than a minimal set of the OSSv4 API. It does not allow altering
of all parameters and will only work when 44100Hz/s16le is used.

View File

@ -193,6 +193,9 @@ struct Vfs::Oss_file_system::Audio
Audio(Audio const &);
Audio &operator = (Audio const &);
bool _audio_out_enabled { true };
bool _audio_in_enabled { true };
bool _audio_out_started { false };
bool _audio_in_started { false };
@ -208,6 +211,23 @@ struct Vfs::Oss_file_system::Audio
size_t _read_sample_offset { 0 };
size_t _write_sample_offset { 0 };
void _start_input()
{
if (!_audio_in_started && _audio_in_enabled) {
_in->start();
_audio_in_started = true;
}
}
void _start_output()
{
if (!_audio_out_started && _audio_out_enabled) {
_out[0]->start();
_out[1]->start();
_audio_out_started = true;
}
}
public:
Audio(Genode::Env &env,
@ -302,6 +322,28 @@ struct Vfs::Oss_file_system::Audio
}
}
void enable_input(bool enable)
{
if (enable) {
_audio_in_enabled = true;
_start_input();
} else {
halt_input();
_audio_in_enabled = false;
}
}
void enable_output(bool enable)
{
if (enable) {
_audio_out_enabled = true;
_start_output();
} else {
halt_output();
_audio_out_enabled = false;
}
}
/*
* Handle Audio_out progress signal.
*
@ -404,10 +446,7 @@ struct Vfs::Oss_file_system::Audio
{
out_size = 0;
if (!_audio_in_started) {
_in->start();
_audio_in_started = true;
}
_start_input();
if (_info.ifrag_bytes == 0) {
/* block */
@ -493,11 +532,7 @@ struct Vfs::Oss_file_system::Audio
return false;
}
if (!_audio_out_started) {
_audio_out_started = true;
_out[0]->start();
_out[1]->start();
}
_start_output();
unsigned stream_samples_written = 0;
@ -756,6 +791,8 @@ struct Vfs::Oss_file_system::Local_factory : File_system_factory
Readonly_value_file_system<long long> _optr_samples_fs { "optr_samples", 0LL };
Readonly_value_file_system<unsigned> _optr_fifo_samples_fs { "optr_fifo_samples", 0U };
Value_file_system<unsigned> _play_underruns_fs { "play_underruns", 0U };
Value_file_system<unsigned> _enable_input_fs { "enable_input", 1U };
Value_file_system<unsigned> _enable_output_fs { "enable_output", 1U };
/* WO files */
Value_file_system<unsigned> _halt_input_fs { "halt_input", 0U };
@ -773,6 +810,18 @@ struct Vfs::Oss_file_system::Local_factory : File_system_factory
Audio _audio { _env.env(), _info, _info_fs };
Genode::Watch_handler<Vfs::Oss_file_system::Local_factory> _enable_input_handler {
_enable_input_fs, "/enable_input",
_env.alloc(),
*this,
&Vfs::Oss_file_system::Local_factory::_enable_input_changed };
Genode::Watch_handler<Vfs::Oss_file_system::Local_factory> _enable_output_handler {
_enable_output_fs, "/enable_output",
_env.alloc(),
*this,
&Vfs::Oss_file_system::Local_factory::_enable_output_changed };
Genode::Watch_handler<Vfs::Oss_file_system::Local_factory> _halt_input_handler {
_halt_input_fs, "/halt_input",
_env.alloc(),
@ -829,6 +878,18 @@ struct Vfs::Oss_file_system::Local_factory : File_system_factory
** Watch handlers **
********************/
void _enable_input_changed()
{
bool enable = (bool)_enable_input_fs.value();
_audio.enable_input(enable);
}
void _enable_output_changed()
{
bool enable = (bool)_enable_output_fs.value();
_audio.enable_output(enable);
}
void _halt_input_changed()
{
_audio.halt_input();
@ -988,6 +1049,14 @@ struct Vfs::Oss_file_system::Local_factory : File_system_factory
if (node.has_type(Value_file_system<unsigned>::type_name())) {
if (_enable_input_fs.matches(node)) {
return &_enable_input_fs;
}
if (_enable_output_fs.matches(node)) {
return &_enable_output_fs;
}
if (_halt_input_fs.matches(node)) {
return &_halt_input_fs;
}
@ -1060,6 +1129,14 @@ class Vfs::Oss_file_system::Compound_file_system : private Local_factory,
xml.attribute("name", "format");
});
xml.node("value", [&] {
xml.attribute("name", "enable_input");
});
xml.node("value", [&] {
xml.attribute("name", "enable_output");
});
xml.node("value", [&] {
xml.attribute("name", "halt_input");
});