asctl.cpp 6.7 KB

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