Serenity Operating System
at master 166 lines 6.9 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, kleines Filmröllchen <filmroellchen@serenityos.org> 4 * Copyright (c) 2021, David Isaksson <davidisaksson93@gmail.com> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/Variant.h> 10#include <AK/Vector.h> 11#include <LibAudio/ConnectionToServer.h> 12#include <LibCore/ArgsParser.h> 13#include <LibCore/EventLoop.h> 14#include <LibCore/System.h> 15#include <LibMain/Main.h> 16#include <math.h> 17#include <stdio.h> 18#include <sys/ioctl.h> 19 20enum AudioVariable : u32 { 21 Volume, 22 Mute, 23 SampleRate 24}; 25 26// asctl: audio server control utility 27ErrorOr<int> serenity_main(Main::Arguments arguments) 28{ 29 Core::EventLoop loop; 30 auto audio_client = TRY(Audio::ConnectionToServer::try_create()); 31 audio_client->async_pause_playback(); 32 33 DeprecatedString command = DeprecatedString::empty(); 34 Vector<StringView> command_arguments; 35 bool human_mode = false; 36 37 Core::ArgsParser args_parser; 38 args_parser.set_general_help("Send control signals to the audio server and hardware."); 39 args_parser.add_option(human_mode, "Print human-readable output", "human-readable", 'h'); 40 args_parser.add_positional_argument(command, "Command, either (g)et or (s)et\n\n\tThe get command accepts a list of variables to print.\n\tThey are printed in the given order.\n\tIf no value is specified, all are printed.\n\n\tThe set command accepts a any number of variables\n\tfollowed by the value they should be set to.\n\n\tPossible variables are (v)olume, (m)ute, sample(r)ate.\n", "command"); 41 args_parser.add_positional_argument(command_arguments, "Arguments for the command", "args", Core::ArgsParser::Required::No); 42 args_parser.parse(arguments); 43 44 TRY(Core::System::unveil(nullptr, nullptr)); 45 TRY(Core::System::pledge("stdio rpath wpath recvfd thread")); 46 47 if (command.equals_ignoring_ascii_case("get"sv) || command == "g") { 48 // Get variables 49 Vector<AudioVariable> values_to_print; 50 if (command_arguments.is_empty()) { 51 values_to_print.append(AudioVariable::Volume); 52 values_to_print.append(AudioVariable::Mute); 53 values_to_print.append(AudioVariable::SampleRate); 54 } else { 55 for (auto& variable : command_arguments) { 56 if (variable.is_one_of("v"sv, "volume"sv)) 57 values_to_print.append(AudioVariable::Volume); 58 else if (variable.is_one_of("m"sv, "mute"sv)) 59 values_to_print.append(AudioVariable::Mute); 60 else if (variable.is_one_of("r"sv, "samplerate"sv)) 61 values_to_print.append(AudioVariable::SampleRate); 62 else { 63 warnln("Error: Unrecognized variable {}", variable); 64 return 1; 65 } 66 } 67 } 68 69 for (auto to_print : values_to_print) { 70 switch (to_print) { 71 case AudioVariable::Volume: { 72 auto volume = static_cast<int>(round(audio_client->get_main_mix_volume() * 100)); 73 if (human_mode) 74 outln("Volume: {}%", volume); 75 else 76 out("{} ", volume); 77 break; 78 } 79 case AudioVariable::Mute: { 80 bool muted = audio_client->is_main_mix_muted(); 81 if (human_mode) 82 outln("Muted: {}", muted ? "Yes" : "No"); 83 else 84 out("{} ", muted ? 1 : 0); 85 break; 86 } 87 case AudioVariable::SampleRate: { 88 u32 sample_rate = audio_client->get_sample_rate(); 89 if (human_mode) 90 outln("Sample rate: {:5d} Hz", sample_rate); 91 else 92 out("{} ", sample_rate); 93 break; 94 } 95 } 96 } 97 if (!human_mode) 98 outln(); 99 } else if (command.equals_ignoring_ascii_case("set"sv) || command == "s") { 100 // Set variables 101 HashMap<AudioVariable, Variant<int, bool>> values_to_set; 102 for (size_t i = 0; i < command_arguments.size(); ++i) { 103 if (i == command_arguments.size() - 1) { 104 warnln("Error: value missing for last variable"); 105 return 1; 106 } 107 auto& variable = command_arguments[i]; 108 if (variable.is_one_of("v"sv, "volume"sv)) { 109 auto volume = command_arguments[++i].to_int(); 110 if (!volume.has_value()) { 111 warnln("Error: {} is not an integer volume", command_arguments[i - 1]); 112 return 1; 113 } 114 if (volume.value() < 0 || volume.value() > 100) { 115 warnln("Error: {} is not between 0 and 100", command_arguments[i - 1]); 116 return 1; 117 } 118 values_to_set.set(AudioVariable::Volume, volume.value()); 119 } else if (variable.is_one_of("m"sv, "mute"sv)) { 120 auto& mute_text = command_arguments[++i]; 121 bool mute; 122 if (mute_text.equals_ignoring_ascii_case("true"sv) || mute_text == "1") { 123 mute = true; 124 } else if (mute_text.equals_ignoring_ascii_case("false"sv) || mute_text == "0") { 125 mute = false; 126 } else { 127 warnln("Error: {} is not one of {{0, 1, true, false}}", mute_text); 128 return 1; 129 } 130 values_to_set.set(AudioVariable::Mute, mute); 131 } else if (variable.is_one_of("r"sv, "samplerate"sv)) { 132 auto sample_rate = command_arguments[++i].to_int(); 133 if (!sample_rate.has_value()) { 134 warnln("Error: {} is not an integer sample rate", command_arguments[i - 1]); 135 return 1; 136 } 137 values_to_set.set(AudioVariable::SampleRate, sample_rate.value()); 138 } else { 139 warnln("Error: Unrecognized variable {}", command_arguments[i]); 140 return 1; 141 } 142 } 143 144 for (auto to_set : values_to_set) { 145 switch (to_set.key) { 146 case AudioVariable::Volume: { 147 int& volume = to_set.value.get<int>(); 148 audio_client->set_main_mix_volume(static_cast<double>(volume) / 100); 149 break; 150 } 151 case AudioVariable::Mute: { 152 bool& mute = to_set.value.get<bool>(); 153 audio_client->set_main_mix_muted(mute); 154 break; 155 } 156 case AudioVariable::SampleRate: { 157 int& sample_rate = to_set.value.get<int>(); 158 audio_client->set_sample_rate(sample_rate); 159 break; 160 } 161 } 162 } 163 } 164 165 return 0; 166}