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 }; 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; handled = true;

View File

@ -71,6 +71,14 @@ presents all files:
* halt_output (wo): writing anything into this file halts output processing. * halt_output (wo): writing anything into this file halts output processing.
Corresponding OSS commands: SNDCTL_DSP_HALT 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 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 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. 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(Audio const &);
Audio &operator = (Audio const &); Audio &operator = (Audio const &);
bool _audio_out_enabled { true };
bool _audio_in_enabled { true };
bool _audio_out_started { false }; bool _audio_out_started { false };
bool _audio_in_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 _read_sample_offset { 0 };
size_t _write_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: public:
Audio(Genode::Env &env, 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. * Handle Audio_out progress signal.
* *
@ -404,10 +446,7 @@ struct Vfs::Oss_file_system::Audio
{ {
out_size = 0; out_size = 0;
if (!_audio_in_started) { _start_input();
_in->start();
_audio_in_started = true;
}
if (_info.ifrag_bytes == 0) { if (_info.ifrag_bytes == 0) {
/* block */ /* block */
@ -493,11 +532,7 @@ struct Vfs::Oss_file_system::Audio
return false; return false;
} }
if (!_audio_out_started) { _start_output();
_audio_out_started = true;
_out[0]->start();
_out[1]->start();
}
unsigned stream_samples_written = 0; 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<long long> _optr_samples_fs { "optr_samples", 0LL };
Readonly_value_file_system<unsigned> _optr_fifo_samples_fs { "optr_fifo_samples", 0U }; 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> _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 */ /* WO files */
Value_file_system<unsigned> _halt_input_fs { "halt_input", 0U }; 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 }; 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 { Genode::Watch_handler<Vfs::Oss_file_system::Local_factory> _halt_input_handler {
_halt_input_fs, "/halt_input", _halt_input_fs, "/halt_input",
_env.alloc(), _env.alloc(),
@ -829,6 +878,18 @@ struct Vfs::Oss_file_system::Local_factory : File_system_factory
** Watch handlers ** ** 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() void _halt_input_changed()
{ {
_audio.halt_input(); _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 (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)) { if (_halt_input_fs.matches(node)) {
return &_halt_input_fs; return &_halt_input_fs;
} }
@ -1060,6 +1129,14 @@ class Vfs::Oss_file_system::Compound_file_system : private Local_factory,
xml.attribute("name", "format"); xml.attribute("name", "format");
}); });
xml.node("value", [&] {
xml.attribute("name", "enable_input");
});
xml.node("value", [&] {
xml.attribute("name", "enable_output");
});
xml.node("value", [&] { xml.node("value", [&] {
xml.attribute("name", "halt_input"); xml.attribute("name", "halt_input");
}); });