1/*** 2 This file is part of PulseAudio. 3 4 Copyright 2004-2006 Lennart Poettering 5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 6 7 PulseAudio is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published 9 by the Free Software Foundation; either version 2.1 of the License, 10 or (at your option) any later version. 11 12 PulseAudio is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 25#include <stdio.h> 26#include <string.h> 27#include <stdlib.h> 28#include <errno.h> 29#include <unistd.h> 30#include <ltdl.h> 31#include <sys/stat.h> 32#include <dirent.h> 33#include <time.h> 34#include <fcntl.h> 35#include <ctype.h> 36 37#include <pulse/xmalloc.h> 38#include <pulse/error.h> 39 40#include <pulsecore/module.h> 41#include <pulsecore/sink.h> 42#include <pulsecore/source.h> 43#include <pulsecore/client.h> 44#include <pulsecore/sink-input.h> 45#include <pulsecore/source-output.h> 46#include <pulsecore/tokenizer.h> 47#include <pulsecore/strbuf.h> 48#include <pulsecore/namereg.h> 49#include <pulsecore/cli-text.h> 50#include <pulsecore/core-scache.h> 51#include <pulsecore/sound-file.h> 52#include <pulsecore/play-memchunk.h> 53#include <pulsecore/sound-file-stream.h> 54#include <pulsecore/shared.h> 55#include <pulsecore/core-util.h> 56#include <pulsecore/message-handler.h> 57#include <pulsecore/core-error.h> 58#include <pulsecore/modinfo.h> 59#include <pulsecore/dynarray.h> 60 61#include "cli-command.h" 62 63struct command { 64 const char *name; 65 int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, bool *fail); 66 const char *help; 67 unsigned args; 68}; 69 70#define META_INCLUDE ".include" 71#define META_FAIL ".fail" 72#define META_NOFAIL ".nofail" 73#define META_IFEXISTS ".ifexists" 74#define META_ELSE ".else" 75#define META_ENDIF ".endif" 76 77enum { 78 IFSTATE_NONE = -1, 79 IFSTATE_FALSE = 0, 80 IFSTATE_TRUE = 1, 81}; 82 83/* Prototypes for all available commands */ 84static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 85static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 86static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 87static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 88static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 89static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 90static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 91static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 92static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 93static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 94static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 95static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 96static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 97static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 98static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 99static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 100static int pa_cli_command_source_output_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 101static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 102static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 103static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 104static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 105static int pa_cli_command_source_output_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 106static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 107static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 108static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 109static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 110static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 111static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 112static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 113static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 114static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 115static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 116static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 117static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 118static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 119static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 120static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 121static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 122static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 123static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 124static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 125static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 126static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 127static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 128static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 129static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 130static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 131static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 132static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 133static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 134static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 135static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 136static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 137static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 138static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 139static int pa_cli_command_send_message_to_object(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail); 140 141/* A method table for all available commands */ 142 143static const struct command commands[] = { 144 { "help", pa_cli_command_help, "Show this help", 1 }, 145 { "list-modules", pa_cli_command_modules, "List loaded modules", 1 }, 146 { "list-cards", pa_cli_command_cards, "List cards", 1 }, 147 { "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, 148 { "list-sources", pa_cli_command_sources, "List loaded sources", 1 }, 149 { "list-clients", pa_cli_command_clients, "List loaded clients", 1 }, 150 { "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, 151 { "list-source-outputs", pa_cli_command_source_outputs, "List source outputs", 1 }, 152 { "stat", pa_cli_command_stat, "Show memory block statistics", 1 }, 153 { "info", pa_cli_command_info, "Show comprehensive status", 1 }, 154 { "ls", pa_cli_command_info, NULL, 1 }, 155 { "list", pa_cli_command_info, NULL, 1 }, 156 { "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, 157 { "unload-module", pa_cli_command_unload, "Unload a module (args: index|name)", 2}, 158 { "describe-module", pa_cli_command_describe, "Describe a module (arg: name)", 2}, 159 { "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, 160 { "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3}, 161 { "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, bool)", 3}, 162 { "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, bool)", 3}, 163 { "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index, volume)", 3}, 164 { "set-source-output-volume",pa_cli_command_source_output_volume,"Set the volume of a source output (args: index, volume)", 3}, 165 { "set-sink-input-mute", pa_cli_command_sink_input_mute, "Set the mute switch of a sink input (args: index, bool)", 3}, 166 { "set-source-output-mute", pa_cli_command_source_output_mute, "Set the mute switch of a source output (args: index, bool)", 3}, 167 { "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, 168 { "set-default-source", pa_cli_command_source_default, "Set the default source (args: index|name)", 2}, 169 { "set-card-profile", pa_cli_command_card_profile, "Change the profile of a card (args: index|name, profile-name)", 3}, 170 { "set-sink-port", pa_cli_command_sink_port, "Change the port of a sink (args: index|name, port-name)", 3}, 171 { "set-source-port", pa_cli_command_source_port, "Change the port of a source (args: index|name, port-name)", 3}, 172 { "set-port-latency-offset", pa_cli_command_port_offset, "Change the latency of a port (args: card-index|card-name, port-name, latency-offset)", 4}, 173 { "suspend-sink", pa_cli_command_suspend_sink, "Suspend sink (args: index|name, bool)", 3}, 174 { "suspend-source", pa_cli_command_suspend_source, "Suspend source (args: index|name, bool)", 3}, 175 { "suspend", pa_cli_command_suspend, "Suspend all sinks and all sources (args: bool)", 2}, 176 { "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3}, 177 { "move-source-output", pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3}, 178 { "update-sink-proplist", pa_cli_command_update_sink_proplist, "Update the properties of a sink (args: index|name, properties)", 3}, 179 { "update-source-proplist", pa_cli_command_update_source_proplist, "Update the properties of a source (args: index|name, properties)", 3}, 180 { "update-sink-input-proplist", pa_cli_command_update_sink_input_proplist, "Update the properties of a sink input (args: index, properties)", 3}, 181 { "update-source-output-proplist", pa_cli_command_update_source_output_proplist, "Update the properties of a source output (args: index, properties)", 3}, 182 { "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1}, 183 { "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3}, 184 { "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2}, 185 { "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3}, 186 { "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3}, 187 { "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2}, 188 { "kill-client", pa_cli_command_kill_client, "Kill a client (args: index)", 2}, 189 { "kill-sink-input", pa_cli_command_kill_sink_input, "Kill a sink input (args: index)", 2}, 190 { "kill-source-output", pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2}, 191 { "set-log-target", pa_cli_command_log_target, "Change the log target (args: null|auto|syslog|stderr|file:PATH|newfile:PATH)", 2}, 192 { "set-log-level", pa_cli_command_log_level, "Change the log level (args: numeric level)", 2}, 193 { "set-log-meta", pa_cli_command_log_meta, "Show source code location in log messages (args: bool)", 2}, 194 { "set-log-time", pa_cli_command_log_time, "Show timestamps in log messages (args: bool)", 2}, 195 { "set-log-backtrace", pa_cli_command_log_backtrace, "Show backtrace in log messages (args: frames)", 2}, 196 { "send-message", pa_cli_command_send_message_to_object, "Send a message to an object (args: recipient, message, message_parameters)", 4}, 197 { "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3}, 198 { "dump", pa_cli_command_dump, "Dump daemon configuration", 1}, 199 { "dump-volumes", pa_cli_command_dump_volumes, "Debug: Show the state of all volumes", 1 }, 200 { "shared", pa_cli_command_list_shared_props, "Debug: Show shared properties", 1}, 201 { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, 202 { "vacuum", pa_cli_command_vacuum, NULL, 1}, 203 { NULL, NULL, NULL, 0 } 204}; 205 206static const char whitespace[] = " \t\n\r"; 207static const char linebreak[] = "\n\r"; 208 209static uint32_t parse_index(const char *n) { 210 uint32_t idx; 211 212 if (pa_atou(n, &idx) < 0) 213 return (uint32_t) PA_IDXSET_INVALID; 214 215 return idx; 216} 217 218static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 219 pa_core_assert_ref(c); 220 pa_assert(t); 221 pa_assert(buf); 222 pa_assert(fail); 223 224 if (pa_core_exit(c, false, 0) < 0) 225 pa_strbuf_puts(buf, "Not allowed to terminate daemon.\n"); 226 227 return 0; 228} 229 230static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 231 const struct command*command; 232 233 pa_core_assert_ref(c); 234 pa_assert(t); 235 pa_assert(buf); 236 pa_assert(fail); 237 238 pa_strbuf_puts(buf, "Available commands:\n"); 239 240 for (command = commands; command->name; command++) 241 if (command->help) 242 pa_strbuf_printf(buf, " %-25s %s\n", command->name, command->help); 243 return 0; 244} 245 246static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 247 char *s; 248 249 pa_core_assert_ref(c); 250 pa_assert(t); 251 pa_assert(buf); 252 pa_assert(fail); 253 254 pa_assert_se(s = pa_module_list_to_string(c)); 255 pa_strbuf_puts(buf, s); 256 pa_xfree(s); 257 return 0; 258} 259 260static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 261 char *s; 262 263 pa_core_assert_ref(c); 264 pa_assert(t); 265 pa_assert(buf); 266 pa_assert(fail); 267 268 pa_assert_se(s = pa_client_list_to_string(c)); 269 pa_strbuf_puts(buf, s); 270 pa_xfree(s); 271 return 0; 272} 273 274static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 275 char *s; 276 277 pa_core_assert_ref(c); 278 pa_assert(t); 279 pa_assert(buf); 280 pa_assert(fail); 281 282 pa_assert_se(s = pa_card_list_to_string(c)); 283 pa_strbuf_puts(buf, s); 284 pa_xfree(s); 285 return 0; 286} 287 288static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 289 char *s; 290 291 pa_core_assert_ref(c); 292 pa_assert(t); 293 pa_assert(buf); 294 pa_assert(fail); 295 296 pa_assert_se(s = pa_sink_list_to_string(c)); 297 pa_strbuf_puts(buf, s); 298 pa_xfree(s); 299 return 0; 300} 301 302static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 303 char *s; 304 305 pa_core_assert_ref(c); 306 pa_assert(t); 307 pa_assert(buf); 308 pa_assert(fail); 309 310 pa_assert_se(s = pa_source_list_to_string(c)); 311 pa_strbuf_puts(buf, s); 312 pa_xfree(s); 313 return 0; 314} 315 316static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 317 char *s; 318 319 pa_core_assert_ref(c); 320 pa_assert(t); 321 pa_assert(buf); 322 pa_assert(fail); 323 324 pa_assert_se(s = pa_sink_input_list_to_string(c)); 325 pa_strbuf_puts(buf, s); 326 pa_xfree(s); 327 return 0; 328} 329 330static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 331 char *s; 332 333 pa_core_assert_ref(c); 334 pa_assert(t); 335 pa_assert(buf); 336 pa_assert(fail); 337 338 pa_assert_se(s = pa_source_output_list_to_string(c)); 339 pa_strbuf_puts(buf, s); 340 pa_xfree(s); 341 return 0; 342} 343 344static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 345 char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; 346 char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; 347 char bytes[PA_BYTES_SNPRINT_MAX]; 348 const pa_mempool_stat *mstat; 349 unsigned k; 350 351 static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = { 352 [PA_MEMBLOCK_POOL] = "POOL", 353 [PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL", 354 [PA_MEMBLOCK_APPENDED] = "APPENDED", 355 [PA_MEMBLOCK_USER] = "USER", 356 [PA_MEMBLOCK_FIXED] = "FIXED", 357 [PA_MEMBLOCK_IMPORTED] = "IMPORTED", 358 }; 359 360 pa_core_assert_ref(c); 361 pa_assert(t); 362 pa_assert(buf); 363 pa_assert(fail); 364 365 mstat = pa_mempool_get_stat(c->mempool); 366 367 pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n", 368 (unsigned) pa_atomic_load(&mstat->n_allocated), 369 pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->allocated_size))); 370 371 pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n", 372 (unsigned) pa_atomic_load(&mstat->n_accumulated), 373 pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->accumulated_size))); 374 375 pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n", 376 (unsigned) pa_atomic_load(&mstat->n_imported), 377 pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->imported_size))); 378 379 pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n", 380 (unsigned) pa_atomic_load(&mstat->n_exported), 381 pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->exported_size))); 382 383 pa_strbuf_printf(buf, "Total sample cache size: %s.\n", 384 pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_scache_total_size(c))); 385 386 pa_strbuf_printf(buf, "Default sample spec: %s\n", 387 pa_sample_spec_snprint(ss, sizeof(ss), &c->default_sample_spec)); 388 389 pa_strbuf_printf(buf, "Default channel map: %s\n", 390 pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map)); 391 392 pa_strbuf_printf(buf, "Default sink name: %s\n" 393 "Default source name: %s\n", 394 c->default_sink ? c->default_sink->name : "none", 395 c->default_source ? c->default_source->name : "none"); 396 397 for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++) 398 pa_strbuf_printf(buf, 399 "Memory blocks of type %s: %u allocated/%u accumulated.\n", 400 type_table[k], 401 (unsigned) pa_atomic_load(&mstat->n_allocated_by_type[k]), 402 (unsigned) pa_atomic_load(&mstat->n_accumulated_by_type[k])); 403 404 return 0; 405} 406 407static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 408 pa_core_assert_ref(c); 409 pa_assert(t); 410 pa_assert(buf); 411 pa_assert(fail); 412 413 pa_cli_command_stat(c, t, buf, fail); 414 pa_cli_command_modules(c, t, buf, fail); 415 pa_cli_command_sinks(c, t, buf, fail); 416 pa_cli_command_sources(c, t, buf, fail); 417 pa_cli_command_clients(c, t, buf, fail); 418 pa_cli_command_cards(c, t, buf, fail); 419 pa_cli_command_sink_inputs(c, t, buf, fail); 420 pa_cli_command_source_outputs(c, t, buf, fail); 421 pa_cli_command_scache_list(c, t, buf, fail); 422 return 0; 423} 424 425static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 426 const char *name; 427 pa_error_code_t err; 428 pa_module *m = NULL; 429 430 pa_core_assert_ref(c); 431 pa_assert(t); 432 pa_assert(buf); 433 pa_assert(fail); 434 435 if (!(name = pa_tokenizer_get(t, 1))) { 436 pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n"); 437 return -1; 438 } 439 440 if ((err = pa_module_load(&m, c, name, pa_tokenizer_get(t, 2))) < 0) { 441 if (err == PA_ERR_EXIST) { 442 pa_strbuf_puts(buf, "Module already loaded; ignoring.\n"); 443 } else { 444 pa_strbuf_puts(buf, "Module load failed.\n"); 445 return -1; 446 } 447 } 448 449 return 0; 450} 451 452static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 453 pa_module *m; 454 uint32_t idx; 455 const char *i; 456 bool unloaded = false; 457 458 pa_core_assert_ref(c); 459 pa_assert(t); 460 pa_assert(buf); 461 pa_assert(fail); 462 463 if (!(i = pa_tokenizer_get(t, 1))) { 464 pa_strbuf_puts(buf, "You need to specify the module index or name.\n"); 465 return -1; 466 } 467 468 if (pa_atou(i, &idx) >= 0) { 469 if (!(m = pa_idxset_get_by_index(c->modules, idx))) { 470 pa_strbuf_puts(buf, "Invalid module index.\n"); 471 return -1; 472 } 473 474 pa_module_unload(m, false); 475 476 } else { 477 PA_IDXSET_FOREACH(m, c->modules, idx) 478 if (pa_streq(i, m->name)) { 479 unloaded = true; 480 pa_module_unload(m, false); 481 } 482 483 if (unloaded == false) { 484 pa_strbuf_printf(buf, "Module %s not loaded.\n", i); 485 return -1; 486 } 487 } 488 489 return 0; 490} 491 492static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 493 const char *name; 494 pa_modinfo *i; 495 496 pa_core_assert_ref(c); 497 pa_assert(t); 498 pa_assert(buf); 499 pa_assert(fail); 500 501 if (!(name = pa_tokenizer_get(t, 1))) { 502 pa_strbuf_puts(buf, "You need to specify the module name.\n"); 503 return -1; 504 } 505 506 if ((i = pa_modinfo_get_by_name(name))) { 507 508 pa_strbuf_printf(buf, "Name: %s\n", name); 509 510 if (!i->description && !i->version && !i->author && !i->usage) 511 pa_strbuf_printf(buf, "No module information available\n"); 512 else { 513 if (i->version) 514 pa_strbuf_printf(buf, "Version: %s\n", i->version); 515 if (i->description) 516 pa_strbuf_printf(buf, "Description: %s\n", i->description); 517 if (i->author) 518 pa_strbuf_printf(buf, "Author: %s\n", i->author); 519 if (i->usage) 520 pa_strbuf_printf(buf, "Usage: %s\n", i->usage); 521 pa_strbuf_printf(buf, "Load Once: %s\n", pa_yes_no(i->load_once)); 522 if (i->deprecated) 523 pa_strbuf_printf(buf, "Warning, deprecated: %s\n", i->deprecated); 524 } 525 526 pa_modinfo_free(i); 527 } else 528 pa_strbuf_puts(buf, "Failed to open module.\n"); 529 530 return 0; 531} 532 533static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 534 const char *n, *v; 535 pa_sink *sink; 536 uint32_t volume; 537 pa_cvolume cvolume; 538 539 pa_core_assert_ref(c); 540 pa_assert(t); 541 pa_assert(buf); 542 pa_assert(fail); 543 544 if (!(n = pa_tokenizer_get(t, 1))) { 545 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); 546 return -1; 547 } 548 549 if (!(v = pa_tokenizer_get(t, 2))) { 550 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n"); 551 return -1; 552 } 553 554 if (pa_atou(v, &volume) < 0) { 555 pa_strbuf_puts(buf, "Failed to parse volume.\n"); 556 return -1; 557 } 558 559 if (!PA_VOLUME_IS_VALID(volume)) { 560 pa_strbuf_puts(buf, "Volume outside permissible range.\n"); 561 return -1; 562 } 563 564 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { 565 pa_strbuf_puts(buf, "No sink found by this name or index.\n"); 566 return -1; 567 } 568 569 pa_cvolume_set(&cvolume, 1, volume); 570 pa_sink_set_volume(sink, &cvolume, true, true); 571 return 0; 572} 573 574static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 575 const char *n, *v; 576 pa_sink_input *si; 577 pa_volume_t volume; 578 pa_cvolume cvolume; 579 uint32_t idx; 580 581 pa_core_assert_ref(c); 582 pa_assert(t); 583 pa_assert(buf); 584 pa_assert(fail); 585 586 if (!(n = pa_tokenizer_get(t, 1))) { 587 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); 588 return -1; 589 } 590 591 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 592 pa_strbuf_puts(buf, "Failed to parse index.\n"); 593 return -1; 594 } 595 596 if (!(v = pa_tokenizer_get(t, 2))) { 597 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n"); 598 return -1; 599 } 600 601 if (pa_atou(v, &volume) < 0) { 602 pa_strbuf_puts(buf, "Failed to parse volume.\n"); 603 return -1; 604 } 605 606 if (!PA_VOLUME_IS_VALID(volume)) { 607 pa_strbuf_puts(buf, "Volume outside permissible range.\n"); 608 return -1; 609 } 610 611 if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) { 612 pa_strbuf_puts(buf, "No sink input found with this index.\n"); 613 return -1; 614 } 615 616 if (!si->volume_writable) { 617 pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n"); 618 return -1; 619 } 620 621 pa_cvolume_set(&cvolume, 1, volume); 622 pa_sink_input_set_volume(si, &cvolume, true, true); 623 return 0; 624} 625 626static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 627 const char *n, *v; 628 pa_source *source; 629 uint32_t volume; 630 pa_cvolume cvolume; 631 632 pa_core_assert_ref(c); 633 pa_assert(t); 634 pa_assert(buf); 635 pa_assert(fail); 636 637 if (!(n = pa_tokenizer_get(t, 1))) { 638 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); 639 return -1; 640 } 641 642 if (!(v = pa_tokenizer_get(t, 2))) { 643 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n"); 644 return -1; 645 } 646 647 if (pa_atou(v, &volume) < 0) { 648 pa_strbuf_puts(buf, "Failed to parse volume.\n"); 649 return -1; 650 } 651 652 if (!PA_VOLUME_IS_VALID(volume)) { 653 pa_strbuf_puts(buf, "Volume outside permissible range.\n"); 654 return -1; 655 } 656 657 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) { 658 pa_strbuf_puts(buf, "No source found by this name or index.\n"); 659 return -1; 660 } 661 662 pa_cvolume_set(&cvolume, 1, volume); 663 pa_source_set_volume(source, &cvolume, true, true); 664 return 0; 665} 666 667static int pa_cli_command_source_output_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 668 const char *n, *v; 669 pa_source_output *so; 670 pa_volume_t volume; 671 pa_cvolume cvolume; 672 uint32_t idx; 673 674 pa_core_assert_ref(c); 675 pa_assert(t); 676 pa_assert(buf); 677 pa_assert(fail); 678 679 if (!(n = pa_tokenizer_get(t, 1))) { 680 pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); 681 return -1; 682 } 683 684 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 685 pa_strbuf_puts(buf, "Failed to parse index.\n"); 686 return -1; 687 } 688 689 if (!(v = pa_tokenizer_get(t, 2))) { 690 pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n"); 691 return -1; 692 } 693 694 if (pa_atou(v, &volume) < 0) { 695 pa_strbuf_puts(buf, "Failed to parse volume.\n"); 696 return -1; 697 } 698 699 if (!PA_VOLUME_IS_VALID(volume)) { 700 pa_strbuf_puts(buf, "Volume outside permissible range.\n"); 701 return -1; 702 } 703 704 if (!(so = pa_idxset_get_by_index(c->source_outputs, idx))) { 705 pa_strbuf_puts(buf, "No source output found with this index.\n"); 706 return -1; 707 } 708 709 if (!so->volume_writable) { 710 pa_strbuf_puts(buf, "This source output's volume can't be changed.\n"); 711 return -1; 712 } 713 714 pa_cvolume_set(&cvolume, 1, volume); 715 pa_source_output_set_volume(so, &cvolume, true, true); 716 return 0; 717} 718 719static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 720 const char *n, *m; 721 pa_sink *sink; 722 int mute; 723 724 pa_core_assert_ref(c); 725 pa_assert(t); 726 pa_assert(buf); 727 pa_assert(fail); 728 729 if (!(n = pa_tokenizer_get(t, 1))) { 730 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); 731 return -1; 732 } 733 734 if (!(m = pa_tokenizer_get(t, 2))) { 735 pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); 736 return -1; 737 } 738 739 if ((mute = pa_parse_boolean(m)) < 0) { 740 pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); 741 return -1; 742 } 743 744 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { 745 pa_strbuf_puts(buf, "No sink found by this name or index.\n"); 746 return -1; 747 } 748 749 pa_sink_set_mute(sink, mute, true); 750 return 0; 751} 752 753static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 754 const char *n, *m; 755 pa_source *source; 756 int mute; 757 758 pa_core_assert_ref(c); 759 pa_assert(t); 760 pa_assert(buf); 761 pa_assert(fail); 762 763 if (!(n = pa_tokenizer_get(t, 1))) { 764 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); 765 return -1; 766 } 767 768 if (!(m = pa_tokenizer_get(t, 2))) { 769 pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); 770 return -1; 771 } 772 773 if ((mute = pa_parse_boolean(m)) < 0) { 774 pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); 775 return -1; 776 } 777 778 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) { 779 pa_strbuf_puts(buf, "No sink found by this name or index.\n"); 780 return -1; 781 } 782 783 pa_source_set_mute(source, mute, true); 784 return 0; 785} 786 787static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 788 const char *n, *s; 789 pa_sink *sink; 790 pa_proplist *p; 791 792 pa_core_assert_ref(c); 793 pa_assert(t); 794 pa_assert(buf); 795 pa_assert(fail); 796 797 if (!(n = pa_tokenizer_get(t, 1))) { 798 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); 799 return -1; 800 } 801 802 if (!(s = pa_tokenizer_get(t, 2))) { 803 pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n"); 804 return -1; 805 } 806 807 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { 808 pa_strbuf_puts(buf, "No sink found by this name or index.\n"); 809 return -1; 810 } 811 812 if (!(p = pa_proplist_from_string(s))) { 813 pa_strbuf_puts(buf, "Failed to parse proplist.\n"); 814 return -1; 815 } 816 817 pa_sink_update_proplist(sink, PA_UPDATE_REPLACE, p); 818 819 pa_proplist_free(p); 820 821 return 0; 822} 823 824static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 825 const char *n, *s; 826 pa_source *source; 827 pa_proplist *p; 828 829 pa_core_assert_ref(c); 830 pa_assert(t); 831 pa_assert(buf); 832 pa_assert(fail); 833 834 if (!(n = pa_tokenizer_get(t, 1))) { 835 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); 836 return -1; 837 } 838 839 if (!(s = pa_tokenizer_get(t, 2))) { 840 pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n"); 841 return -1; 842 } 843 844 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) { 845 pa_strbuf_puts(buf, "No source found by this name or index.\n"); 846 return -1; 847 } 848 849 if (!(p = pa_proplist_from_string(s))) { 850 pa_strbuf_puts(buf, "Failed to parse proplist.\n"); 851 return -1; 852 } 853 854 pa_source_update_proplist(source, PA_UPDATE_REPLACE, p); 855 856 pa_proplist_free(p); 857 858 return 0; 859} 860 861static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 862 const char *n, *s; 863 pa_sink_input *si; 864 uint32_t idx; 865 pa_proplist *p; 866 867 pa_core_assert_ref(c); 868 pa_assert(t); 869 pa_assert(buf); 870 pa_assert(fail); 871 872 if (!(n = pa_tokenizer_get(t, 1))) { 873 pa_strbuf_puts(buf, "You need to specify a sink input either by index.\n"); 874 return -1; 875 } 876 877 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 878 pa_strbuf_puts(buf, "Failed to parse index.\n"); 879 return -1; 880 } 881 882 if (!(s = pa_tokenizer_get(t, 2))) { 883 pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n"); 884 return -1; 885 } 886 887 if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) { 888 pa_strbuf_puts(buf, "No sink input found with this index.\n"); 889 return -1; 890 } 891 892 if (!(p = pa_proplist_from_string(s))) { 893 pa_strbuf_puts(buf, "Failed to parse proplist.\n"); 894 return -1; 895 } 896 897 pa_sink_input_update_proplist(si, PA_UPDATE_REPLACE, p); 898 899 pa_proplist_free(p); 900 901 return 0; 902} 903 904static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 905 const char *n, *s; 906 pa_source_output *so; 907 uint32_t idx; 908 pa_proplist *p; 909 910 pa_core_assert_ref(c); 911 pa_assert(t); 912 pa_assert(buf); 913 pa_assert(fail); 914 915 if (!(n = pa_tokenizer_get(t, 1))) { 916 pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); 917 return -1; 918 } 919 920 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 921 pa_strbuf_puts(buf, "Failed to parse index.\n"); 922 return -1; 923 } 924 925 if (!(s = pa_tokenizer_get(t, 2))) { 926 pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n"); 927 return -1; 928 } 929 930 if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) { 931 pa_strbuf_puts(buf, "No source output found with this index.\n"); 932 return -1; 933 } 934 935 if (!(p = pa_proplist_from_string(s))) { 936 pa_strbuf_puts(buf, "Failed to parse proplist.\n"); 937 return -1; 938 } 939 940 pa_source_output_update_proplist(so, PA_UPDATE_REPLACE, p); 941 942 pa_proplist_free(p); 943 944 return 0; 945} 946 947static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 948 const char *n, *v; 949 pa_sink_input *si; 950 uint32_t idx; 951 int mute; 952 953 pa_core_assert_ref(c); 954 pa_assert(t); 955 pa_assert(buf); 956 pa_assert(fail); 957 958 if (!(n = pa_tokenizer_get(t, 1))) { 959 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); 960 return -1; 961 } 962 963 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 964 pa_strbuf_puts(buf, "Failed to parse index.\n"); 965 return -1; 966 } 967 968 if (!(v = pa_tokenizer_get(t, 2))) { 969 pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); 970 return -1; 971 } 972 973 if ((mute = pa_parse_boolean(v)) < 0) { 974 pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); 975 return -1; 976 } 977 978 if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) { 979 pa_strbuf_puts(buf, "No sink input found with this index.\n"); 980 return -1; 981 } 982 983 pa_sink_input_set_mute(si, mute, true); 984 return 0; 985} 986 987static int pa_cli_command_source_output_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 988 const char *n, *v; 989 pa_source_output *so; 990 uint32_t idx; 991 int mute; 992 993 pa_core_assert_ref(c); 994 pa_assert(t); 995 pa_assert(buf); 996 pa_assert(fail); 997 998 if (!(n = pa_tokenizer_get(t, 1))) { 999 pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); 1000 return -1; 1001 } 1002 1003 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 1004 pa_strbuf_puts(buf, "Failed to parse index.\n"); 1005 return -1; 1006 } 1007 1008 if (!(v = pa_tokenizer_get(t, 2))) { 1009 pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n"); 1010 return -1; 1011 } 1012 1013 if ((mute = pa_parse_boolean(v)) < 0) { 1014 pa_strbuf_puts(buf, "Failed to parse mute switch.\n"); 1015 return -1; 1016 } 1017 1018 if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) { 1019 pa_strbuf_puts(buf, "No source output found with this index.\n"); 1020 return -1; 1021 } 1022 1023 pa_source_output_set_mute(so, mute, true); 1024 return 0; 1025} 1026 1027static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1028 const char *n; 1029 pa_sink *s; 1030 1031 pa_core_assert_ref(c); 1032 pa_assert(t); 1033 pa_assert(buf); 1034 pa_assert(fail); 1035 1036 if (!(n = pa_tokenizer_get(t, 1))) { 1037 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); 1038 return -1; 1039 } 1040 1041 if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK))) 1042 pa_core_set_configured_default_sink(c, s->name); 1043 else 1044 pa_strbuf_printf(buf, "Sink %s does not exist.\n", n); 1045 1046 return 0; 1047} 1048 1049static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1050 const char *n; 1051 pa_source *s; 1052 1053 pa_core_assert_ref(c); 1054 pa_assert(t); 1055 pa_assert(buf); 1056 pa_assert(fail); 1057 1058 if (!(n = pa_tokenizer_get(t, 1))) { 1059 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); 1060 return -1; 1061 } 1062 1063 if ((s = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) 1064 pa_core_set_configured_default_source(c, s->name); 1065 else 1066 pa_strbuf_printf(buf, "Source %s does not exist.\n", n); 1067 return 0; 1068} 1069 1070static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1071 const char *n; 1072 pa_client *client; 1073 uint32_t idx; 1074 1075 pa_core_assert_ref(c); 1076 pa_assert(t); 1077 pa_assert(buf); 1078 pa_assert(fail); 1079 1080 if (!(n = pa_tokenizer_get(t, 1))) { 1081 pa_strbuf_puts(buf, "You need to specify a client by its index.\n"); 1082 return -1; 1083 } 1084 1085 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 1086 pa_strbuf_puts(buf, "Failed to parse index.\n"); 1087 return -1; 1088 } 1089 1090 if (!(client = pa_idxset_get_by_index(c->clients, idx))) { 1091 pa_strbuf_puts(buf, "No client found by this index.\n"); 1092 return -1; 1093 } 1094 1095 pa_client_kill(client); 1096 return 0; 1097} 1098 1099static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1100 const char *n; 1101 pa_sink_input *sink_input; 1102 uint32_t idx; 1103 1104 pa_core_assert_ref(c); 1105 pa_assert(t); 1106 pa_assert(buf); 1107 pa_assert(fail); 1108 1109 if (!(n = pa_tokenizer_get(t, 1))) { 1110 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); 1111 return -1; 1112 } 1113 1114 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 1115 pa_strbuf_puts(buf, "Failed to parse index.\n"); 1116 return -1; 1117 } 1118 1119 if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) { 1120 pa_strbuf_puts(buf, "No sink input found by this index.\n"); 1121 return -1; 1122 } 1123 1124 pa_sink_input_kill(sink_input); 1125 return 0; 1126} 1127 1128static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1129 const char *n; 1130 pa_source_output *source_output; 1131 uint32_t idx; 1132 1133 pa_core_assert_ref(c); 1134 pa_assert(t); 1135 pa_assert(buf); 1136 pa_assert(fail); 1137 1138 if (!(n = pa_tokenizer_get(t, 1))) { 1139 pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); 1140 return -1; 1141 } 1142 1143 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 1144 pa_strbuf_puts(buf, "Failed to parse index.\n"); 1145 return -1; 1146 } 1147 1148 if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) { 1149 pa_strbuf_puts(buf, "No source output found by this index.\n"); 1150 return -1; 1151 } 1152 1153 pa_source_output_kill(source_output); 1154 return 0; 1155} 1156 1157static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1158 char *s; 1159 1160 pa_core_assert_ref(c); 1161 pa_assert(t); 1162 pa_assert(buf); 1163 pa_assert(fail); 1164 1165 pa_assert_se(s = pa_scache_list_to_string(c)); 1166 pa_strbuf_puts(buf, s); 1167 pa_xfree(s); 1168 1169 return 0; 1170} 1171 1172static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1173 const char *n, *sink_name; 1174 pa_sink *sink; 1175 uint32_t idx; 1176 1177 pa_core_assert_ref(c); 1178 pa_assert(t); 1179 pa_assert(buf); 1180 pa_assert(fail); 1181 1182 if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { 1183 pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n"); 1184 return -1; 1185 } 1186 1187 if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) { 1188 pa_strbuf_puts(buf, "No sink by that name.\n"); 1189 return -1; 1190 } 1191 1192 if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM, NULL, &idx) < 0) { 1193 pa_strbuf_puts(buf, "Failed to play sample.\n"); 1194 return -1; 1195 } 1196 1197 pa_strbuf_printf(buf, "Playing on sink input #%i\n", idx); 1198 1199 return 0; 1200} 1201 1202static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1203 const char *n; 1204 1205 pa_core_assert_ref(c); 1206 pa_assert(t); 1207 pa_assert(buf); 1208 pa_assert(fail); 1209 1210 if (!(n = pa_tokenizer_get(t, 1))) { 1211 pa_strbuf_puts(buf, "You need to specify a sample name.\n"); 1212 return -1; 1213 } 1214 1215 if (pa_scache_remove_item(c, n) < 0) { 1216 pa_strbuf_puts(buf, "Failed to remove sample.\n"); 1217 return -1; 1218 } 1219 1220 return 0; 1221} 1222 1223static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1224 const char *fname, *n; 1225 int r; 1226 1227 pa_core_assert_ref(c); 1228 pa_assert(t); 1229 pa_assert(buf); 1230 pa_assert(fail); 1231 1232 if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) { 1233 pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n"); 1234 return -1; 1235 } 1236 1237 if (strstr(pa_tokenizer_get(t, 0), "lazy")) 1238 r = pa_scache_add_file_lazy(c, n, fname, NULL); 1239 else 1240 r = pa_scache_add_file(c, n, fname, NULL); 1241 1242 if (r < 0) 1243 pa_strbuf_puts(buf, "Failed to load sound file.\n"); 1244 1245 return 0; 1246} 1247 1248static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1249 const char *pname; 1250 1251 pa_core_assert_ref(c); 1252 pa_assert(t); 1253 pa_assert(buf); 1254 pa_assert(fail); 1255 1256 if (!(pname = pa_tokenizer_get(t, 1))) { 1257 pa_strbuf_puts(buf, "You need to specify a path name.\n"); 1258 return -1; 1259 } 1260 1261 if (pa_scache_add_directory_lazy(c, pname) < 0) { 1262 pa_strbuf_puts(buf, "Failed to load directory.\n"); 1263 return -1; 1264 } 1265 1266 return 0; 1267} 1268 1269static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1270 const char *fname, *sink_name; 1271 pa_sink *sink; 1272 1273 pa_core_assert_ref(c); 1274 pa_assert(t); 1275 pa_assert(buf); 1276 pa_assert(fail); 1277 1278 if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) { 1279 pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n"); 1280 return -1; 1281 } 1282 1283 if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) { 1284 pa_strbuf_puts(buf, "No sink by that name.\n"); 1285 return -1; 1286 } 1287#ifdef SNDFILE_ENABLE 1288 if (pa_play_file(sink, fname, NULL) < 0) { 1289 pa_strbuf_puts(buf, "Failed to play sound file.\n"); 1290 return -1; 1291 } 1292#else 1293 return -1; 1294#endif 1295 return 0; 1296} 1297 1298static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1299 pa_core_assert_ref(c); 1300 pa_assert(t); 1301 pa_assert(buf); 1302 pa_assert(fail); 1303 1304 pa_shared_dump(c, buf); 1305 return 0; 1306} 1307 1308static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1309 pa_core_assert_ref(c); 1310 pa_assert(t); 1311 pa_assert(buf); 1312 pa_assert(fail); 1313 1314 pa_mempool_vacuum(c->mempool); 1315 1316 return 0; 1317} 1318 1319static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1320 const char *n, *k; 1321 pa_sink_input *si; 1322 pa_sink *sink; 1323 uint32_t idx; 1324 1325 pa_core_assert_ref(c); 1326 pa_assert(t); 1327 pa_assert(buf); 1328 pa_assert(fail); 1329 1330 if (!(n = pa_tokenizer_get(t, 1))) { 1331 pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); 1332 return -1; 1333 } 1334 1335 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 1336 pa_strbuf_puts(buf, "Failed to parse index.\n"); 1337 return -1; 1338 } 1339 1340 if (!(k = pa_tokenizer_get(t, 2))) { 1341 pa_strbuf_puts(buf, "You need to specify a sink.\n"); 1342 return -1; 1343 } 1344 1345 if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) { 1346 pa_strbuf_puts(buf, "No sink input found with this index.\n"); 1347 return -1; 1348 } 1349 1350 if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK))) { 1351 pa_strbuf_puts(buf, "No sink found by this name or index.\n"); 1352 return -1; 1353 } 1354 1355 if (pa_sink_input_move_to(si, sink, true) < 0) { 1356 pa_strbuf_puts(buf, "Moved failed.\n"); 1357 return -1; 1358 } 1359 return 0; 1360} 1361 1362static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1363 const char *n, *k; 1364 pa_source_output *so; 1365 pa_source *source; 1366 uint32_t idx; 1367 1368 pa_core_assert_ref(c); 1369 pa_assert(t); 1370 pa_assert(buf); 1371 pa_assert(fail); 1372 1373 if (!(n = pa_tokenizer_get(t, 1))) { 1374 pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); 1375 return -1; 1376 } 1377 1378 if ((idx = parse_index(n)) == PA_IDXSET_INVALID) { 1379 pa_strbuf_puts(buf, "Failed to parse index.\n"); 1380 return -1; 1381 } 1382 1383 if (!(k = pa_tokenizer_get(t, 2))) { 1384 pa_strbuf_puts(buf, "You need to specify a source.\n"); 1385 return -1; 1386 } 1387 1388 if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) { 1389 pa_strbuf_puts(buf, "No source output found with this index.\n"); 1390 return -1; 1391 } 1392 1393 if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE))) { 1394 pa_strbuf_puts(buf, "No source found by this name or index.\n"); 1395 return -1; 1396 } 1397 1398 if (pa_source_output_move_to(so, source, true) < 0) { 1399 pa_strbuf_puts(buf, "Moved failed.\n"); 1400 return -1; 1401 } 1402 return 0; 1403} 1404 1405static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1406 const char *n, *m; 1407 pa_sink *sink; 1408 int suspend, r; 1409 1410 pa_core_assert_ref(c); 1411 pa_assert(t); 1412 pa_assert(buf); 1413 pa_assert(fail); 1414 1415 if (!(n = pa_tokenizer_get(t, 1))) { 1416 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); 1417 return -1; 1418 } 1419 1420 if (!(m = pa_tokenizer_get(t, 2))) { 1421 pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n"); 1422 return -1; 1423 } 1424 1425 if ((suspend = pa_parse_boolean(m)) < 0) { 1426 pa_strbuf_puts(buf, "Failed to parse suspend switch.\n"); 1427 return -1; 1428 } 1429 1430 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { 1431 pa_strbuf_puts(buf, "No sink found by this name or index.\n"); 1432 return -1; 1433 } 1434 1435 pa_log_debug("%s of sink %s requested via CLI.", suspend ? "Suspending" : "Resuming", sink->name); 1436 1437 if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0) 1438 pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", pa_strerror(r)); 1439 1440 return 0; 1441} 1442 1443static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1444 const char *n, *m; 1445 pa_source *source; 1446 int suspend, r; 1447 1448 pa_core_assert_ref(c); 1449 pa_assert(t); 1450 pa_assert(buf); 1451 pa_assert(fail); 1452 1453 if (!(n = pa_tokenizer_get(t, 1))) { 1454 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); 1455 return -1; 1456 } 1457 1458 if (!(m = pa_tokenizer_get(t, 2))) { 1459 pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n"); 1460 return -1; 1461 } 1462 1463 if ((suspend = pa_parse_boolean(m)) < 0) { 1464 pa_strbuf_puts(buf, "Failed to parse suspend switch.\n"); 1465 return -1; 1466 } 1467 1468 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) { 1469 pa_strbuf_puts(buf, "No source found by this name or index.\n"); 1470 return -1; 1471 } 1472 1473 pa_log_debug("%s of source %s requested via CLI.", suspend ? "Suspending" : "Resuming", source->name); 1474 1475 if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0) 1476 pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", pa_strerror(r)); 1477 1478 return 0; 1479} 1480 1481static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1482 const char *m; 1483 int suspend, r; 1484 1485 pa_core_assert_ref(c); 1486 pa_assert(t); 1487 pa_assert(buf); 1488 pa_assert(fail); 1489 1490 if (!(m = pa_tokenizer_get(t, 1))) { 1491 pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n"); 1492 return -1; 1493 } 1494 1495 if ((suspend = pa_parse_boolean(m)) < 0) { 1496 pa_strbuf_puts(buf, "Failed to parse suspend switch.\n"); 1497 return -1; 1498 } 1499 1500 pa_log_debug("%s of all sinks and sources requested via CLI.", suspend ? "Suspending" : "Resuming"); 1501 1502 if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0) 1503 pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", pa_strerror(r)); 1504 1505 if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0) 1506 pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", pa_strerror(r)); 1507 1508 return 0; 1509} 1510 1511static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1512 const char *m; 1513 pa_log_target *log_target = NULL; 1514 1515 pa_core_assert_ref(c); 1516 pa_assert(t); 1517 pa_assert(buf); 1518 pa_assert(fail); 1519 1520 if (!(m = pa_tokenizer_get(t, 1))) { 1521 pa_strbuf_puts(buf, "You need to specify a log target (null|auto|syslog|stderr|file:PATH|newfile:PATH).\n"); 1522 return -1; 1523 } 1524 1525 /* 'auto' is actually the effect with 'stderr' */ 1526 if (pa_streq(m, "auto")) 1527 log_target = pa_log_target_new(PA_LOG_STDERR, NULL); 1528 else { 1529 log_target = pa_log_parse_target(m); 1530 1531 if (!log_target) { 1532 pa_strbuf_puts(buf, "Invalid log target.\n"); 1533 return -1; 1534 } 1535 } 1536 1537 if (pa_log_set_target(log_target) < 0) { 1538 pa_strbuf_puts(buf, "Failed to set log target.\n"); 1539 pa_log_target_free(log_target); 1540 return -1; 1541 } 1542 1543 pa_log_target_free(log_target); 1544 1545 return 0; 1546} 1547 1548static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1549 const char *m; 1550 uint32_t level; 1551 1552 pa_core_assert_ref(c); 1553 pa_assert(t); 1554 pa_assert(buf); 1555 pa_assert(fail); 1556 1557 if (!(m = pa_tokenizer_get(t, 1))) { 1558 pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n"); 1559 return -1; 1560 } 1561 1562 if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) { 1563 pa_strbuf_puts(buf, "Failed to parse log level.\n"); 1564 return -1; 1565 } 1566 1567 pa_log_set_level(level); 1568 1569 return 0; 1570} 1571 1572static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1573 const char *m; 1574 int b; 1575 1576 pa_core_assert_ref(c); 1577 pa_assert(t); 1578 pa_assert(buf); 1579 pa_assert(fail); 1580 1581 if (!(m = pa_tokenizer_get(t, 1))) { 1582 pa_strbuf_puts(buf, "You need to specify a boolean.\n"); 1583 return -1; 1584 } 1585 1586 if ((b = pa_parse_boolean(m)) < 0) { 1587 pa_strbuf_puts(buf, "Failed to parse log meta switch.\n"); 1588 return -1; 1589 } 1590 1591 pa_log_set_flags(PA_LOG_PRINT_META, b ? PA_LOG_SET : PA_LOG_UNSET); 1592 1593 return 0; 1594} 1595 1596static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1597 const char *m; 1598 int b; 1599 1600 pa_core_assert_ref(c); 1601 pa_assert(t); 1602 pa_assert(buf); 1603 pa_assert(fail); 1604 1605 if (!(m = pa_tokenizer_get(t, 1))) { 1606 pa_strbuf_puts(buf, "You need to specify a boolean.\n"); 1607 return -1; 1608 } 1609 1610 if ((b = pa_parse_boolean(m)) < 0) { 1611 pa_strbuf_puts(buf, "Failed to parse log meta switch.\n"); 1612 return -1; 1613 } 1614 1615 pa_log_set_flags(PA_LOG_PRINT_TIME, b ? PA_LOG_SET : PA_LOG_UNSET); 1616 1617 return 0; 1618} 1619 1620static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1621 const char *m; 1622 uint32_t nframes; 1623 1624 pa_core_assert_ref(c); 1625 pa_assert(t); 1626 pa_assert(buf); 1627 pa_assert(fail); 1628 1629 if (!(m = pa_tokenizer_get(t, 1))) { 1630 pa_strbuf_puts(buf, "You need to specify a backtrace level.\n"); 1631 return -1; 1632 } 1633 1634 if (pa_atou(m, &nframes) < 0 || nframes >= 1000) { 1635 pa_strbuf_puts(buf, "Failed to parse backtrace level.\n"); 1636 return -1; 1637 } 1638 1639 pa_log_set_show_backtrace(nframes); 1640 1641 return 0; 1642} 1643 1644static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1645 const char *n, *p; 1646 pa_card *card; 1647 pa_card_profile *profile; 1648 1649 pa_core_assert_ref(c); 1650 pa_assert(t); 1651 pa_assert(buf); 1652 pa_assert(fail); 1653 1654 if (!(n = pa_tokenizer_get(t, 1))) { 1655 pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n"); 1656 return -1; 1657 } 1658 1659 if (!(p = pa_tokenizer_get(t, 2))) { 1660 pa_strbuf_puts(buf, "You need to specify a profile by its name.\n"); 1661 return -1; 1662 } 1663 1664 if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) { 1665 pa_strbuf_puts(buf, "No card found by this name or index.\n"); 1666 return -1; 1667 } 1668 1669 if (!(profile = pa_hashmap_get(card->profiles, p))) { 1670 pa_strbuf_printf(buf, "No such profile: %s\n", p); 1671 return -1; 1672 } 1673 1674 if (pa_card_set_profile(card, profile, true) < 0) { 1675 pa_strbuf_printf(buf, "Failed to set card profile to '%s'.\n", p); 1676 return -1; 1677 } 1678 1679 return 0; 1680} 1681 1682static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1683 const char *n, *p; 1684 pa_sink *sink; 1685 1686 pa_core_assert_ref(c); 1687 pa_assert(t); 1688 pa_assert(buf); 1689 pa_assert(fail); 1690 1691 if (!(n = pa_tokenizer_get(t, 1))) { 1692 pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); 1693 return -1; 1694 } 1695 1696 if (!(p = pa_tokenizer_get(t, 2))) { 1697 pa_strbuf_puts(buf, "You need to specify a profile by its name.\n"); 1698 return -1; 1699 } 1700 1701 if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { 1702 pa_strbuf_puts(buf, "No sink found by this name or index.\n"); 1703 return -1; 1704 } 1705 1706 if (pa_sink_set_port(sink, p, true) < 0) { 1707 pa_strbuf_printf(buf, "Failed to set sink port to '%s'.\n", p); 1708 return -1; 1709 } 1710 1711 return 0; 1712} 1713 1714static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1715 const char *n, *p; 1716 pa_source *source; 1717 1718 pa_core_assert_ref(c); 1719 pa_assert(t); 1720 pa_assert(buf); 1721 pa_assert(fail); 1722 1723 if (!(n = pa_tokenizer_get(t, 1))) { 1724 pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); 1725 return -1; 1726 } 1727 1728 if (!(p = pa_tokenizer_get(t, 2))) { 1729 pa_strbuf_puts(buf, "You need to specify a profile by its name.\n"); 1730 return -1; 1731 } 1732 1733 if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) { 1734 pa_strbuf_puts(buf, "No source found by this name or index.\n"); 1735 return -1; 1736 } 1737 1738 if (pa_source_set_port(source, p, true) < 0) { 1739 pa_strbuf_printf(buf, "Failed to set source port to '%s'.\n", p); 1740 return -1; 1741 } 1742 1743 return 0; 1744} 1745 1746static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1747 const char *n, *p, *l; 1748 pa_device_port *port; 1749 pa_card *card; 1750 int32_t offset; 1751 1752 pa_core_assert_ref(c); 1753 pa_assert(t); 1754 pa_assert(buf); 1755 pa_assert(fail); 1756 1757 if (!(n = pa_tokenizer_get(t, 1))) { 1758 pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n"); 1759 return -1; 1760 } 1761 1762 if (!(p = pa_tokenizer_get(t, 2))) { 1763 pa_strbuf_puts(buf, "You need to specify a port by its name.\n"); 1764 return -1; 1765 } 1766 1767 if (!(l = pa_tokenizer_get(t, 3))) { 1768 pa_strbuf_puts(buf, "You need to specify a latency offset.\n"); 1769 return -1; 1770 } 1771 1772 if (pa_atoi(l, &offset) < 0) { 1773 pa_strbuf_puts(buf, "Failed to parse the latency offset.\n"); 1774 return -1; 1775 } 1776 1777 if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) { 1778 pa_strbuf_puts(buf, "No card found by this name or index.\n"); 1779 return -1; 1780 } 1781 1782 if (!(port = pa_hashmap_get(card->ports, p))) { 1783 pa_strbuf_puts(buf, "No port found by this name.\n"); 1784 return -1; 1785 } 1786 1787 pa_device_port_set_latency_offset(port, offset); 1788 1789 return 0; 1790} 1791 1792static int pa_cli_command_send_message_to_object(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1793 const char *object_path, *message, *message_parameters; 1794 char *response = NULL; 1795 int ret; 1796 1797 pa_core_assert_ref(c); 1798 pa_assert(t); 1799 pa_assert(buf); 1800 pa_assert(fail); 1801 1802 1803 if (!(object_path = pa_tokenizer_get(t, 1))) { 1804 pa_strbuf_puts(buf, "You need to specify an object path as recipient for the message.\n"); 1805 return -1; 1806 } 1807 1808 if (!(message = pa_tokenizer_get(t, 2))) { 1809 pa_strbuf_puts(buf, "You need to specify a message name.\n"); 1810 return -1; 1811 } 1812 1813 /* parameters may be NULL */ 1814 message_parameters = pa_tokenizer_get(t, 3); 1815 1816 ret = pa_message_handler_send_message(c, object_path, message, message_parameters, &response); 1817 1818 if (ret < 0) { 1819 pa_strbuf_printf(buf, "Send message failed: %s\n", pa_strerror(ret)); 1820 ret = -1; 1821 1822 } else { 1823 if (response) 1824 pa_strbuf_puts(buf, response); 1825 pa_strbuf_puts(buf, "\n"); 1826 ret = 0; 1827 } 1828 1829 pa_xfree(response); 1830 return ret; 1831} 1832 1833static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1834 pa_module *m; 1835 pa_sink *sink; 1836 pa_source *source; 1837 pa_card *card; 1838 bool nl; 1839 uint32_t idx; 1840 time_t now; 1841#ifdef HAVE_CTIME_R 1842 char txt[256]; 1843#endif 1844 1845 pa_core_assert_ref(c); 1846 pa_assert(t); 1847 pa_assert(buf); 1848 pa_assert(fail); 1849 1850 time(&now); 1851 1852#ifdef HAVE_CTIME_R 1853 pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt)); 1854#else 1855 pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now)); 1856#endif 1857 1858 PA_IDXSET_FOREACH(m, c->modules, idx) { 1859 1860 pa_strbuf_printf(buf, "load-module %s", m->name); 1861 1862 if (m->argument) 1863 pa_strbuf_printf(buf, " %s", m->argument); 1864 1865 pa_strbuf_puts(buf, "\n"); 1866 } 1867 1868 nl = false; 1869 PA_IDXSET_FOREACH(sink, c->sinks, idx) { 1870 1871 if (!nl) { 1872 pa_strbuf_puts(buf, "\n"); 1873 nl = true; 1874 } 1875 1876 pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, false))); 1877 pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, false))); 1878 pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(sink->state == PA_SINK_SUSPENDED)); 1879 } 1880 1881 nl = false; 1882 PA_IDXSET_FOREACH(source, c->sources, idx) { 1883 1884 if (!nl) { 1885 pa_strbuf_puts(buf, "\n"); 1886 nl = true; 1887 } 1888 1889 pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, false))); 1890 pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, false))); 1891 pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(source->state == PA_SOURCE_SUSPENDED)); 1892 } 1893 1894 nl = false; 1895 PA_IDXSET_FOREACH(card, c->cards, idx) { 1896 1897 if (!nl) { 1898 pa_strbuf_puts(buf, "\n"); 1899 nl = true; 1900 } 1901 1902 pa_strbuf_printf(buf, "set-card-profile %s %s\n", card->name, card->active_profile->name); 1903 } 1904 1905 nl = false; 1906 if (c->default_sink) { 1907 if (!nl) { 1908 pa_strbuf_puts(buf, "\n"); 1909 nl = true; 1910 } 1911 1912 pa_strbuf_printf(buf, "set-default-sink %s\n", c->default_sink->name); 1913 } 1914 1915 if (c->default_source) { 1916 if (!nl) 1917 pa_strbuf_puts(buf, "\n"); 1918 1919 pa_strbuf_printf(buf, "set-default-source %s\n", c->default_source->name); 1920 } 1921 1922 pa_strbuf_puts(buf, "\n### EOF\n"); 1923 1924 return 0; 1925} 1926 1927static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) { 1928 pa_sink *s; 1929 pa_source *so; 1930 pa_sink_input *i; 1931 pa_source_output *o; 1932 uint32_t s_idx, i_idx; 1933 char v_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; 1934 pa_channel_map *map; 1935 1936 pa_core_assert_ref(c); 1937 pa_assert(t); 1938 pa_assert(buf); 1939 pa_assert(fail); 1940 1941 PA_IDXSET_FOREACH(s, c->sinks, s_idx) { 1942 map = &s->channel_map; 1943 pa_strbuf_printf(buf, "Sink %d: ", s_idx); 1944 pa_strbuf_printf(buf, 1945 "reference = %s, ", 1946 pa_cvolume_snprint_verbose(v_str, 1947 sizeof(v_str), 1948 &s->reference_volume, 1949 map, 1950 s->flags & PA_SINK_DECIBEL_VOLUME)); 1951 pa_strbuf_printf(buf, 1952 "real = %s, ", 1953 pa_cvolume_snprint_verbose(v_str, 1954 sizeof(v_str), 1955 &s->real_volume, 1956 &s->channel_map, 1957 s->flags & PA_SINK_DECIBEL_VOLUME)); 1958 pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &s->soft_volume, map, true)); 1959 pa_strbuf_printf(buf, 1960 "current_hw = %s, ", 1961 pa_cvolume_snprint_verbose(v_str, 1962 sizeof(v_str), 1963 &s->thread_info.current_hw_volume, 1964 map, 1965 s->flags & PA_SINK_DECIBEL_VOLUME)); 1966 pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(s->save_volume)); 1967 1968 PA_IDXSET_FOREACH(i, s->inputs, i_idx) { 1969 map = &i->channel_map; 1970 pa_strbuf_printf(buf, "\tInput %d: ", i_idx); 1971 pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume, map, true)); 1972 pa_strbuf_printf(buf, 1973 "reference_ratio = %s, ", 1974 pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->reference_ratio, map, true)); 1975 pa_strbuf_printf(buf, 1976 "real_ratio = %s, ", 1977 pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->real_ratio, map, true)); 1978 pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->soft_volume, map, true)); 1979 pa_strbuf_printf(buf, 1980 "volume_factor = %s, ", 1981 pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume_factor, map, true)); 1982 pa_strbuf_printf(buf, 1983 "volume_factor_sink = %s, ", 1984 pa_cvolume_snprint_verbose(v_str, 1985 sizeof(v_str), 1986 &i->volume_factor_sink, 1987 &i->sink->channel_map, 1988 true)); 1989 pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(i->save_volume)); 1990 } 1991 } 1992 1993 PA_IDXSET_FOREACH(so, c->sources, s_idx) { 1994 map = &so->channel_map; 1995 pa_strbuf_printf(buf, "Source %d: ", s_idx); 1996 pa_strbuf_printf(buf, 1997 "reference = %s, ", 1998 pa_cvolume_snprint_verbose(v_str, 1999 sizeof(v_str), 2000 &so->reference_volume, 2001 map, 2002 so->flags & PA_SOURCE_DECIBEL_VOLUME)); 2003 pa_strbuf_printf(buf, 2004 "real = %s, ", 2005 pa_cvolume_snprint_verbose(v_str, 2006 sizeof(v_str), 2007 &so->real_volume, 2008 map, 2009 so->flags & PA_SOURCE_DECIBEL_VOLUME)); 2010 pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &so->soft_volume, map, true)); 2011 pa_strbuf_printf(buf, 2012 "current_hw = %s, ", 2013 pa_cvolume_snprint_verbose(v_str, 2014 sizeof(v_str), 2015 &so->thread_info.current_hw_volume, 2016 map, 2017 so->flags & PA_SOURCE_DECIBEL_VOLUME)); 2018 pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(so->save_volume)); 2019 2020 PA_IDXSET_FOREACH(o, so->outputs, i_idx) { 2021 map = &o->channel_map; 2022 pa_strbuf_printf(buf, "\tOutput %d: ", i_idx); 2023 pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume, map, true)); 2024 pa_strbuf_printf(buf, 2025 "reference_ratio = %s, ", 2026 pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->reference_ratio, map, true)); 2027 pa_strbuf_printf(buf, 2028 "real_ratio = %s, ", 2029 pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->real_ratio, map, true)); 2030 pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->soft_volume, map, true)); 2031 pa_strbuf_printf(buf, 2032 "volume_factor = %s, ", 2033 pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume_factor, map, true)); 2034 pa_strbuf_printf(buf, 2035 "volume_factor_source = %s, ", 2036 pa_cvolume_snprint_verbose(v_str, 2037 sizeof(v_str), 2038 &o->volume_factor_source, 2039 &o->source->channel_map, 2040 true)); 2041 pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(o->save_volume)); 2042 } 2043 } 2044 2045 return 0; 2046} 2047 2048int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, bool *fail, int *ifstate) { 2049 const char *cs; 2050 2051 pa_assert(c); 2052 pa_assert(s); 2053 pa_assert(buf); 2054 2055 cs = s+strspn(s, whitespace); 2056 2057 if (*cs == '#' || !*cs) 2058 return 0; 2059 else if (*cs == '.') { 2060 if (!strcmp(cs, META_ELSE)) { 2061 if (!ifstate || *ifstate == IFSTATE_NONE) { 2062 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); 2063 return -1; 2064 } else if (*ifstate == IFSTATE_TRUE) 2065 *ifstate = IFSTATE_FALSE; 2066 else 2067 *ifstate = IFSTATE_TRUE; 2068 return 0; 2069 } else if (!strcmp(cs, META_ENDIF)) { 2070 if (!ifstate || *ifstate == IFSTATE_NONE) { 2071 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); 2072 return -1; 2073 } else 2074 *ifstate = IFSTATE_NONE; 2075 return 0; 2076 } 2077 if (ifstate && *ifstate == IFSTATE_FALSE) 2078 return 0; 2079 if (!strcmp(cs, META_FAIL)) 2080 *fail = true; 2081 else if (!strcmp(cs, META_NOFAIL)) 2082 *fail = false; 2083 else { 2084 size_t l; 2085 l = strcspn(cs, whitespace); 2086 2087 if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) { 2088 struct stat st; 2089 const char *fn = cs+l+strspn(cs+l, whitespace); 2090 2091 char *filename; 2092#ifdef OS_IS_WIN32 2093 if (strncmp(fn, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0) 2094 filename = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse" PA_PATH_SEP "%s", 2095 pa_win32_get_toplevel(NULL), 2096 fn + strlen(PA_DEFAULT_CONFIG_DIR)); 2097 else 2098#endif 2099 filename = pa_xstrdup(fn); 2100 2101 if (stat(filename, &st) < 0) { 2102 pa_log_warn("stat('%s'): %s", filename, pa_cstrerror(errno)); 2103 if (*fail) { 2104 pa_xfree(filename); 2105 return -1; 2106 } 2107 } else { 2108 if (S_ISDIR(st.st_mode)) { 2109 DIR *d; 2110 2111 if (!(d = opendir(filename))) { 2112 pa_log_warn("Failed to read '%s': %s", filename, pa_cstrerror(errno)); 2113 if (*fail) { 2114 pa_xfree(filename); 2115 return -1; 2116 } 2117 } else { 2118 unsigned i, count; 2119 char **sorted_files; 2120 struct dirent *de; 2121 bool failed = false; 2122 pa_dynarray *files = pa_dynarray_new(NULL); 2123 2124 while ((de = readdir(d))) { 2125 char *extn; 2126 size_t flen = strlen(de->d_name); 2127 2128 if (flen < 4) 2129 continue; 2130 2131 extn = &de->d_name[flen-3]; 2132 if (strncmp(extn, ".pa", 3) == 0) 2133 pa_dynarray_append(files, pa_sprintf_malloc("%s" PA_PATH_SEP "%s", filename, de->d_name)); 2134 } 2135 2136 closedir(d); 2137 if ((count = pa_dynarray_size(files))) { 2138 sorted_files = pa_xnew(char*, count); 2139 for (i = 0; i < count; ++i) 2140 sorted_files[i] = pa_dynarray_get(files, i); 2141 pa_dynarray_free(files); 2142 2143 for (i = 0; i < count; ++i) { 2144 for (unsigned j = 0; j < count; ++j) { 2145 if (strcmp(sorted_files[i], sorted_files[j]) < 0) { 2146 char *tmp = sorted_files[i]; 2147 sorted_files[i] = sorted_files[j]; 2148 sorted_files[j] = tmp; 2149 } 2150 } 2151 } 2152 2153 for (i = 0; i < count; ++i) { 2154 if (!failed) { 2155 if (pa_cli_command_execute_file(c, sorted_files[i], buf, fail) < 0 && *fail) 2156 failed = true; 2157 } 2158 2159 pa_xfree(sorted_files[i]); 2160 } 2161 pa_xfree(sorted_files); 2162 if (failed) { 2163 pa_xfree(filename); 2164 return -1; 2165 } 2166 } 2167 } 2168 } else if (pa_cli_command_execute_file(c, filename, buf, fail) < 0 && *fail) { 2169 pa_xfree(filename); 2170 return -1; 2171 } 2172 } 2173 pa_xfree(filename); 2174 } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) { 2175 if (!ifstate) { 2176 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs); 2177 return -1; 2178 } else if (*ifstate != IFSTATE_NONE) { 2179 pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs); 2180 return -1; 2181 } else { 2182 const char *filename = cs+l+strspn(cs+l, whitespace); 2183 *ifstate = pa_module_exists(filename) ? IFSTATE_TRUE : IFSTATE_FALSE; 2184 } 2185 } else { 2186 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs); 2187 if (*fail) return -1; 2188 } 2189 } 2190 } else { 2191 const struct command*command; 2192 int unknown = 1; 2193 size_t l; 2194 2195 if (ifstate && *ifstate == IFSTATE_FALSE) 2196 return 0; 2197 2198 l = strcspn(cs, whitespace); 2199 2200 for (command = commands; command->name; command++) 2201 if (strlen(command->name) == l && !strncmp(cs, command->name, l)) { 2202 int ret; 2203 pa_tokenizer *t = pa_tokenizer_new(cs, command->args); 2204 pa_assert(t); 2205 ret = command->proc(c, t, buf, fail); 2206 pa_tokenizer_free(t); 2207 unknown = 0; 2208 2209 if (ret < 0 && *fail) 2210 return -1; 2211 2212 break; 2213 } 2214 2215 if (unknown) { 2216 pa_strbuf_printf(buf, "Unknown command: %s\n", cs); 2217 if (*fail) 2218 return -1; 2219 } 2220 } 2221 2222 return 0; 2223} 2224 2225int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) { 2226 return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL); 2227} 2228 2229int pa_cli_command_execute_file_stream(pa_core *c, FILE *f, pa_strbuf *buf, bool *fail) { 2230 char line[2048]; 2231 int ifstate = IFSTATE_NONE; 2232 int ret = -1; 2233 bool _fail = true; 2234 2235 pa_assert(c); 2236 pa_assert(f); 2237 pa_assert(buf); 2238 2239 if (!fail) 2240 fail = &_fail; 2241 2242 while (fgets(line, sizeof(line), f)) { 2243 pa_strip_nl(line); 2244 2245 if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) 2246 goto fail; 2247 } 2248 2249 ret = 0; 2250 2251fail: 2252 2253 return ret; 2254} 2255 2256int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, bool *fail) { 2257 FILE *f = NULL; 2258 int ret = -1; 2259 bool _fail = true; 2260 2261 pa_assert(c); 2262 pa_assert(fn); 2263 pa_assert(buf); 2264 2265 if (!fail) 2266 fail = &_fail; 2267 2268 if (!(f = pa_fopen_cloexec(fn, "r"))) { 2269 pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno)); 2270 if (!*fail) 2271 ret = 0; 2272 goto fail; 2273 } 2274 2275 pa_log_debug("Parsing script '%s'", fn); 2276 ret = pa_cli_command_execute_file_stream(c, f, buf, fail); 2277 2278fail: 2279 if (f) 2280 fclose(f); 2281 2282 return ret; 2283} 2284 2285int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) { 2286 const char *p; 2287 int ifstate = IFSTATE_NONE; 2288 bool _fail = true; 2289 2290 pa_assert(c); 2291 pa_assert(s); 2292 pa_assert(buf); 2293 2294 if (!fail) 2295 fail = &_fail; 2296 2297 p = s; 2298 while (*p) { 2299 size_t l = strcspn(p, linebreak); 2300 char *line = pa_xstrndup(p, l); 2301 2302 if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) { 2303 pa_xfree(line); 2304 return -1; 2305 } 2306 pa_xfree(line); 2307 2308 p += l; 2309 p += strspn(p, linebreak); 2310 } 2311 2312 return 0; 2313} 2314