2004-07-16 19:56:36 +00:00
|
|
|
/***
|
2006-06-19 21:53:48 +00:00
|
|
|
This file is part of PulseAudio.
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2007-02-13 15:35:19 +00:00
|
|
|
Copyright 2004-2006 Lennart Poettering
|
|
|
|
|
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
|
|
|
|
|
|
2006-06-19 21:53:48 +00:00
|
|
|
PulseAudio is free software; you can redistribute it and/or modify
|
2004-11-14 14:58:54 +00:00
|
|
|
it under the terms of the GNU Lesser General Public License as published
|
2009-03-03 20:23:02 +00:00
|
|
|
by the Free Software Foundation; either version 2.1 of the License,
|
2004-07-16 19:56:36 +00:00
|
|
|
or (at your option) any later version.
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2006-06-19 21:53:48 +00:00
|
|
|
PulseAudio is distributed in the hope that it will be useful, but
|
2004-07-16 19:56:36 +00:00
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
General Public License for more details.
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2004-11-14 14:58:54 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
2014-11-26 14:14:51 +01:00
|
|
|
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
2004-07-16 19:56:36 +00:00
|
|
|
***/
|
|
|
|
|
|
2004-07-16 19:16:42 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <errno.h>
|
2007-05-26 23:39:33 +00:00
|
|
|
#include <unistd.h>
|
2008-03-27 20:52:59 +00:00
|
|
|
#include <ltdl.h>
|
2010-09-04 17:07:23 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <dirent.h>
|
2011-03-01 18:06:28 +01:00
|
|
|
#include <time.h>
|
2012-05-25 10:16:04 +08:00
|
|
|
#include <fcntl.h>
|
2012-05-30 14:27:26 +02:00
|
|
|
#include <ctype.h>
|
2004-07-14 21:52:41 +00:00
|
|
|
|
2006-06-19 21:53:48 +00:00
|
|
|
#include <pulse/xmalloc.h>
|
2009-03-04 05:30:28 +01:00
|
|
|
#include <pulse/error.h>
|
2006-05-17 16:34:18 +00:00
|
|
|
|
2006-06-19 21:53:48 +00:00
|
|
|
#include <pulsecore/module.h>
|
|
|
|
|
#include <pulsecore/sink.h>
|
|
|
|
|
#include <pulsecore/source.h>
|
|
|
|
|
#include <pulsecore/client.h>
|
|
|
|
|
#include <pulsecore/sink-input.h>
|
|
|
|
|
#include <pulsecore/source-output.h>
|
|
|
|
|
#include <pulsecore/tokenizer.h>
|
|
|
|
|
#include <pulsecore/strbuf.h>
|
|
|
|
|
#include <pulsecore/namereg.h>
|
|
|
|
|
#include <pulsecore/cli-text.h>
|
|
|
|
|
#include <pulsecore/core-scache.h>
|
|
|
|
|
#include <pulsecore/sound-file.h>
|
|
|
|
|
#include <pulsecore/play-memchunk.h>
|
|
|
|
|
#include <pulsecore/sound-file-stream.h>
|
2008-08-01 02:10:54 +03:00
|
|
|
#include <pulsecore/shared.h>
|
2006-06-19 21:53:48 +00:00
|
|
|
#include <pulsecore/core-util.h>
|
|
|
|
|
#include <pulsecore/core-error.h>
|
2009-01-19 22:02:28 +01:00
|
|
|
#include <pulsecore/modinfo.h>
|
2010-09-04 17:07:23 +01:00
|
|
|
#include <pulsecore/dynarray.h>
|
2006-02-17 12:10:58 +00:00
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
#include "cli-command.h"
|
|
|
|
|
|
|
|
|
|
struct command {
|
|
|
|
|
const char *name;
|
2013-06-27 19:28:09 +02:00
|
|
|
int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, bool *fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *help;
|
|
|
|
|
unsigned args;
|
|
|
|
|
};
|
|
|
|
|
|
2007-05-26 23:39:33 +00:00
|
|
|
#define META_INCLUDE ".include"
|
|
|
|
|
#define META_FAIL ".fail"
|
|
|
|
|
#define META_NOFAIL ".nofail"
|
|
|
|
|
#define META_IFEXISTS ".ifexists"
|
|
|
|
|
#define META_ELSE ".else"
|
|
|
|
|
#define META_ENDIF ".endif"
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
IFSTATE_NONE = -1,
|
|
|
|
|
IFSTATE_FALSE = 0,
|
|
|
|
|
IFSTATE_TRUE = 1,
|
|
|
|
|
};
|
2004-12-11 00:10:41 +00:00
|
|
|
|
2004-11-21 21:31:28 +00:00
|
|
|
/* Prototypes for all available commands */
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_source_output_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_source_output_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
|
|
|
|
static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail);
|
2004-11-21 21:31:28 +00:00
|
|
|
|
|
|
|
|
/* A method table for all available commands */
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
static const struct command commands[] = {
|
|
|
|
|
{ "help", pa_cli_command_help, "Show this help", 1 },
|
2004-09-14 23:08:39 +00:00
|
|
|
{ "list-modules", pa_cli_command_modules, "List loaded modules", 1 },
|
2012-04-05 11:41:18 +01:00
|
|
|
{ "list-cards", pa_cli_command_cards, "List cards", 1 },
|
2004-09-14 23:08:39 +00:00
|
|
|
{ "list-sinks", pa_cli_command_sinks, "List loaded sinks", 1 },
|
|
|
|
|
{ "list-sources", pa_cli_command_sources, "List loaded sources", 1 },
|
|
|
|
|
{ "list-clients", pa_cli_command_clients, "List loaded clients", 1 },
|
|
|
|
|
{ "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 },
|
|
|
|
|
{ "list-source-outputs", pa_cli_command_source_outputs, "List source outputs", 1 },
|
2004-07-14 21:52:41 +00:00
|
|
|
{ "stat", pa_cli_command_stat, "Show memory block statistics", 1 },
|
|
|
|
|
{ "info", pa_cli_command_info, "Show comprehensive status", 1 },
|
|
|
|
|
{ "ls", pa_cli_command_info, NULL, 1 },
|
|
|
|
|
{ "list", pa_cli_command_info, NULL, 1 },
|
2007-10-28 19:13:50 +00:00
|
|
|
{ "load-module", pa_cli_command_load, "Load a module (args: name, arguments)", 3},
|
2012-05-30 14:27:26 +02:00
|
|
|
{ "unload-module", pa_cli_command_unload, "Unload a module (args: index|name)", 2},
|
2008-05-15 23:34:41 +00:00
|
|
|
{ "describe-module", pa_cli_command_describe, "Describe a module (arg: name)", 2},
|
2007-10-28 19:13:50 +00:00
|
|
|
{ "set-sink-volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3},
|
2006-02-22 14:11:23 +00:00
|
|
|
{ "set-source-volume", pa_cli_command_source_volume, "Set the volume of a source (args: index|name, volume)", 3},
|
2007-10-28 19:13:50 +00:00
|
|
|
{ "set-sink-mute", pa_cli_command_sink_mute, "Set the mute switch of a sink (args: index|name, bool)", 3},
|
|
|
|
|
{ "set-source-mute", pa_cli_command_source_mute, "Set the mute switch of a source (args: index|name, bool)", 3},
|
2012-04-05 11:41:18 +01:00
|
|
|
{ "set-sink-input-volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index, volume)", 3},
|
2012-04-05 11:52:24 +01:00
|
|
|
{ "set-source-output-volume",pa_cli_command_source_output_volume,"Set the volume of a source output (args: index, volume)", 3},
|
2012-04-05 11:41:18 +01:00
|
|
|
{ "set-sink-input-mute", pa_cli_command_sink_input_mute, "Set the mute switch of a sink input (args: index, bool)", 3},
|
2012-04-05 11:52:24 +01:00
|
|
|
{ "set-source-output-mute", pa_cli_command_source_output_mute, "Set the mute switch of a source output (args: index, bool)", 3},
|
2012-04-05 11:41:18 +01:00
|
|
|
{ "set-default-sink", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2},
|
|
|
|
|
{ "set-default-source", pa_cli_command_source_default, "Set the default source (args: index|name)", 2},
|
|
|
|
|
{ "set-card-profile", pa_cli_command_card_profile, "Change the profile of a card (args: index|name, profile-name)", 3},
|
|
|
|
|
{ "set-sink-port", pa_cli_command_sink_port, "Change the port of a sink (args: index|name, port-name)", 3},
|
|
|
|
|
{ "set-source-port", pa_cli_command_source_port, "Change the port of a source (args: index|name, port-name)", 3},
|
2012-06-22 20:55:55 +02:00
|
|
|
{ "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},
|
2012-04-05 11:41:18 +01:00
|
|
|
{ "suspend-sink", pa_cli_command_suspend_sink, "Suspend sink (args: index|name, bool)", 3},
|
|
|
|
|
{ "suspend-source", pa_cli_command_suspend_source, "Suspend source (args: index|name, bool)", 3},
|
|
|
|
|
{ "suspend", pa_cli_command_suspend, "Suspend all sinks and all sources (args: bool)", 2},
|
|
|
|
|
{ "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3},
|
|
|
|
|
{ "move-source-output", pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
|
2008-10-31 18:43:38 +02:00
|
|
|
{ "update-sink-proplist", pa_cli_command_update_sink_proplist, "Update the properties of a sink (args: index|name, properties)", 3},
|
2009-01-13 19:07:59 +02:00
|
|
|
{ "update-source-proplist", pa_cli_command_update_source_proplist, "Update the properties of a source (args: index|name, properties)", 3},
|
|
|
|
|
{ "update-sink-input-proplist", pa_cli_command_update_sink_input_proplist, "Update the properties of a sink input (args: index, properties)", 3},
|
2012-04-05 11:52:24 +01:00
|
|
|
{ "update-source-output-proplist", pa_cli_command_update_source_output_proplist, "Update the properties of a source output (args: index, properties)", 3},
|
2004-09-14 23:08:39 +00:00
|
|
|
{ "list-samples", pa_cli_command_scache_list, "List all entries in the sample cache", 1},
|
|
|
|
|
{ "play-sample", pa_cli_command_scache_play, "Play a sample from the sample cache (args: name, sink|index)", 3},
|
|
|
|
|
{ "remove-sample", pa_cli_command_scache_remove, "Remove a sample from the sample cache (args: name)", 2},
|
|
|
|
|
{ "load-sample", pa_cli_command_scache_load, "Load a sound file into the sample cache (args: name, filename)", 3},
|
2004-11-17 00:05:25 +00:00
|
|
|
{ "load-sample-lazy", pa_cli_command_scache_load, "Lazily load a sound file into the sample cache (args: name, filename)", 3},
|
|
|
|
|
{ "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2},
|
2012-04-05 11:41:18 +01:00
|
|
|
{ "kill-client", pa_cli_command_kill_client, "Kill a client (args: index)", 2},
|
|
|
|
|
{ "kill-sink-input", pa_cli_command_kill_sink_input, "Kill a sink input (args: index)", 2},
|
|
|
|
|
{ "kill-source-output", pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
|
2013-06-19 11:59:08 +08:00
|
|
|
{ "set-log-target", pa_cli_command_log_target, "Change the log target (args: null|auto|syslog|stderr|file:PATH|newfile:PATH)", 2},
|
2008-10-21 19:14:07 +02:00
|
|
|
{ "set-log-level", pa_cli_command_log_level, "Change the log level (args: numeric level)", 2},
|
|
|
|
|
{ "set-log-meta", pa_cli_command_log_meta, "Show source code location in log messages (args: bool)", 2},
|
|
|
|
|
{ "set-log-time", pa_cli_command_log_time, "Show timestamps in log messages (args: bool)", 2},
|
2009-06-17 03:45:14 +02:00
|
|
|
{ "set-log-backtrace", pa_cli_command_log_backtrace, "Show backtrace in log messages (args: frames)", 2},
|
2012-04-05 11:41:18 +01:00
|
|
|
{ "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3},
|
|
|
|
|
{ "dump", pa_cli_command_dump, "Dump daemon configuration", 1},
|
|
|
|
|
{ "dump-volumes", pa_cli_command_dump_volumes, "Debug: Show the state of all volumes", 1 },
|
|
|
|
|
{ "shared", pa_cli_command_list_shared_props, "Debug: Show shared properties", 1},
|
|
|
|
|
{ "exit", pa_cli_command_exit, "Terminate the daemon", 1 },
|
|
|
|
|
{ "vacuum", pa_cli_command_vacuum, NULL, 1},
|
2004-07-14 21:52:41 +00:00
|
|
|
{ NULL, NULL, NULL, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const char whitespace[] = " \t\n\r";
|
|
|
|
|
static const char linebreak[] = "\n\r";
|
|
|
|
|
|
|
|
|
|
static uint32_t parse_index(const char *n) {
|
2006-01-11 01:17:39 +00:00
|
|
|
uint32_t idx;
|
2004-12-11 00:10:41 +00:00
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if (pa_atou(n, &idx) < 0)
|
2004-07-14 21:52:41 +00:00
|
|
|
return (uint32_t) PA_IDXSET_INVALID;
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
return idx;
|
2004-07-14 21:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
if (pa_core_exit(c, false, 0) < 0)
|
2008-08-06 19:39:12 +02:00
|
|
|
pa_strbuf_puts(buf, "Not allowed to terminate daemon.\n");
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const struct command*command;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
pa_strbuf_puts(buf, "Available commands:\n");
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
for (command = commands; command->name; command++)
|
|
|
|
|
if (command->help)
|
2004-09-14 23:08:39 +00:00
|
|
|
pa_strbuf_printf(buf, " %-25s %s\n", command->name, command->help);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
char *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_module_list_to_string(c));
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, s);
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(s);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
char *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_client_list_to_string(c));
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, s);
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(s);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-01-15 18:52:11 +01:00
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_card_list_to_string(c));
|
|
|
|
|
pa_strbuf_puts(buf, s);
|
|
|
|
|
pa_xfree(s);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
char *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_sink_list_to_string(c));
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, s);
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(s);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
char *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_source_list_to_string(c));
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, s);
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(s);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
char *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_sink_input_list_to_string(c));
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, s);
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(s);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
char *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_source_output_list_to_string(c));
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, s);
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(s);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-02-21 16:32:42 +01:00
|
|
|
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];
|
|
|
|
|
char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
|
2009-09-06 22:33:04 +02:00
|
|
|
char bytes[PA_BYTES_SNPRINT_MAX];
|
2010-09-04 17:07:23 +01:00
|
|
|
const pa_mempool_stat *mstat;
|
2006-08-19 16:25:41 +00:00
|
|
|
unsigned k;
|
|
|
|
|
|
|
|
|
|
static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = {
|
|
|
|
|
[PA_MEMBLOCK_POOL] = "POOL",
|
|
|
|
|
[PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL",
|
|
|
|
|
[PA_MEMBLOCK_APPENDED] = "APPENDED",
|
|
|
|
|
[PA_MEMBLOCK_USER] = "USER",
|
|
|
|
|
[PA_MEMBLOCK_FIXED] = "FIXED",
|
|
|
|
|
[PA_MEMBLOCK_IMPORTED] = "IMPORTED",
|
|
|
|
|
};
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-09-07 14:58:42 +00:00
|
|
|
|
2010-09-04 17:07:23 +01:00
|
|
|
mstat = pa_mempool_get_stat(c->mempool);
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2004-09-07 14:58:42 +00:00
|
|
|
pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n",
|
2010-09-04 17:07:23 +01:00
|
|
|
(unsigned) pa_atomic_load(&mstat->n_allocated),
|
|
|
|
|
pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->allocated_size)));
|
2004-09-07 14:58:42 +00:00
|
|
|
|
|
|
|
|
pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n",
|
2010-09-04 17:07:23 +01:00
|
|
|
(unsigned) pa_atomic_load(&mstat->n_accumulated),
|
|
|
|
|
pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->accumulated_size)));
|
2006-08-18 19:55:18 +00:00
|
|
|
|
|
|
|
|
pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n",
|
2010-09-04 17:07:23 +01:00
|
|
|
(unsigned) pa_atomic_load(&mstat->n_imported),
|
|
|
|
|
pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->imported_size)));
|
2004-09-07 14:58:42 +00:00
|
|
|
|
2006-08-18 19:55:18 +00:00
|
|
|
pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n",
|
2010-09-04 17:07:23 +01:00
|
|
|
(unsigned) pa_atomic_load(&mstat->n_exported),
|
|
|
|
|
pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->exported_size)));
|
2004-09-07 14:58:42 +00:00
|
|
|
|
2006-08-18 19:55:18 +00:00
|
|
|
pa_strbuf_printf(buf, "Total sample cache size: %s.\n",
|
2009-09-06 22:33:04 +02:00
|
|
|
pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_scache_total_size(c)));
|
2006-08-18 19:55:18 +00:00
|
|
|
|
|
|
|
|
pa_strbuf_printf(buf, "Default sample spec: %s\n",
|
2009-02-21 16:32:42 +01:00
|
|
|
pa_sample_spec_snprint(ss, sizeof(ss), &c->default_sample_spec));
|
|
|
|
|
|
|
|
|
|
pa_strbuf_printf(buf, "Default channel map: %s\n",
|
|
|
|
|
pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map));
|
2004-09-07 14:58:42 +00:00
|
|
|
|
|
|
|
|
pa_strbuf_printf(buf, "Default sink name: %s\n"
|
|
|
|
|
"Default source name: %s\n",
|
improve default sink/source handling
Currently the default sink policy is simple: either the user has
configured it explicitly, in which case we always use that as the
default, or we pick the sink with the highest priority. The sink
priorities are currently static, so there's no need to worry about
updating the default sink when sink priorities change.
I intend to make things a bit more complex: if the active port of a sink
is unavailable, the sink should not be the default sink, and I also want
to make sink priorities dependent on the active port, so changing the
port should cause re-evaluation of which sink to choose as the default.
Currently the default sink choice is done only when someone calls
pa_namereg_get_default_sink(), and change notifications are only sent
when a sink is created or destroyed. That makes it hard to add new rules
to the default sink selection policy.
This patch moves the default sink selection to
pa_core_update_default_sink(), which is called whenever something
happens that can affect the default sink choice. That function needs to
know the previous choice in order to send change notifications as
appropriate, but previously pa_core.default_sink was only set when the
user had configured it explicitly. Now pa_core.default_sink is always
set (unless there are no sinks at all), so pa_core_update_default_sink()
can use that to get the previous choice. The user configuration is saved
in a new variable, pa_core.configured_default_sink.
pa_namereg_get_default_sink() is now unnecessary, because
pa_core.default_sink can be used directly to get the
currently-considered-best sink. pa_namereg_set_default_sink() is
replaced by pa_core_set_configured_default_sink().
I haven't confirmed it, but I expect that this patch will fix problems
in the D-Bus protocol related to default sink handling. The D-Bus
protocol used to get confused when the current default sink gets
removed. It would incorrectly think that if there's no explicitly
configured default sink, then there's no default sink at all. Even
worse, when the D-Bus thinks that there's no default sink, it concludes
that there are no sinks at all, which made it impossible to configure
the default sink via the D-Bus interface. Now that pa_core.default_sink
is always set, except when there really aren't any sinks, the D-Bus
protocol should behave correctly.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99425
2017-02-16 12:09:38 +02:00
|
|
|
c->default_sink ? c->default_sink->name : "none",
|
|
|
|
|
c->default_source ? c->default_source->name : "none");
|
2004-09-19 23:12:41 +00:00
|
|
|
|
2006-08-19 16:25:41 +00:00
|
|
|
for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++)
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"Memory blocks of type %s: %u allocated/%u accumulated.\n",
|
|
|
|
|
type_table[k],
|
2010-09-04 17:07:23 +01:00
|
|
|
(unsigned) pa_atomic_load(&mstat->n_allocated_by_type[k]),
|
|
|
|
|
(unsigned) pa_atomic_load(&mstat->n_accumulated_by_type[k]));
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2004-12-11 00:10:41 +00:00
|
|
|
pa_cli_command_stat(c, t, buf, fail);
|
|
|
|
|
pa_cli_command_modules(c, t, buf, fail);
|
|
|
|
|
pa_cli_command_sinks(c, t, buf, fail);
|
|
|
|
|
pa_cli_command_sources(c, t, buf, fail);
|
|
|
|
|
pa_cli_command_clients(c, t, buf, fail);
|
2009-01-15 18:52:11 +01:00
|
|
|
pa_cli_command_cards(c, t, buf, fail);
|
2004-12-11 00:10:41 +00:00
|
|
|
pa_cli_command_sink_inputs(c, t, buf, fail);
|
|
|
|
|
pa_cli_command_source_outputs(c, t, buf, fail);
|
|
|
|
|
pa_cli_command_scache_list(c, t, buf, fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *name;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
if (!(name = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2009-02-17 22:07:57 +02:00
|
|
|
if (!pa_module_load(c, name, pa_tokenizer_get(t, 2))) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "Module load failed.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_module *m;
|
|
|
|
|
uint32_t idx;
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *i;
|
2013-06-27 19:28:09 +02:00
|
|
|
bool unloaded = false;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
if (!(i = pa_tokenizer_get(t, 1))) {
|
2012-05-30 14:27:26 +02:00
|
|
|
pa_strbuf_puts(buf, "You need to specify the module index or name.\n");
|
2004-07-14 21:52:41 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-30 14:27:26 +02:00
|
|
|
if (pa_atou(i, &idx) >= 0) {
|
|
|
|
|
if (!(m = pa_idxset_get_by_index(c->modules, idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "Invalid module index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_module_unload_request(m, false);
|
2012-05-30 14:27:26 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
PA_IDXSET_FOREACH(m, c->modules, idx)
|
|
|
|
|
if (pa_streq(i, m->name)) {
|
2013-06-27 19:28:09 +02:00
|
|
|
unloaded = true;
|
|
|
|
|
pa_module_unload_request(m, false);
|
2012-05-30 14:27:26 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
if (unloaded == false) {
|
2012-05-30 14:27:26 +02:00
|
|
|
pa_strbuf_printf(buf, "Module %s not loaded.\n", i);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2004-07-14 21:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2008-05-15 23:34:41 +00:00
|
|
|
const char *name;
|
|
|
|
|
pa_modinfo *i;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(name = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify the module name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((i = pa_modinfo_get_by_name(name))) {
|
|
|
|
|
|
|
|
|
|
pa_strbuf_printf(buf, "Name: %s\n", name);
|
|
|
|
|
|
|
|
|
|
if (!i->description && !i->version && !i->author && !i->usage)
|
|
|
|
|
pa_strbuf_printf(buf, "No module information available\n");
|
|
|
|
|
else {
|
|
|
|
|
if (i->version)
|
|
|
|
|
pa_strbuf_printf(buf, "Version: %s\n", i->version);
|
|
|
|
|
if (i->description)
|
|
|
|
|
pa_strbuf_printf(buf, "Description: %s\n", i->description);
|
|
|
|
|
if (i->author)
|
|
|
|
|
pa_strbuf_printf(buf, "Author: %s\n", i->author);
|
|
|
|
|
if (i->usage)
|
|
|
|
|
pa_strbuf_printf(buf, "Usage: %s\n", i->usage);
|
|
|
|
|
pa_strbuf_printf(buf, "Load Once: %s\n", pa_yes_no(i->load_once));
|
2009-05-28 02:47:36 +02:00
|
|
|
if (i->deprecated)
|
|
|
|
|
pa_strbuf_printf(buf, "Warning, deprecated: %s\n", i->deprecated);
|
2008-05-15 23:34:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_modinfo_free(i);
|
|
|
|
|
} else
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to open module.\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *n, *v;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_sink *sink;
|
2004-12-11 00:10:41 +00:00
|
|
|
uint32_t volume;
|
2006-01-27 16:25:31 +00:00
|
|
|
pa_cvolume cvolume;
|
2004-07-14 21:52:41 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(v = pa_tokenizer_get(t, 2))) {
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
|
2004-07-14 21:52:41 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 00:10:41 +00:00
|
|
|
if (pa_atou(v, &volume) < 0) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse volume.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-09 23:10:00 +05:30
|
|
|
if (!PA_VOLUME_IS_VALID(volume)) {
|
|
|
|
|
pa_strbuf_puts(buf, "Volume outside permissible range.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-31 21:41:36 +02:00
|
|
|
pa_cvolume_set(&cvolume, 1, volume);
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_sink_set_volume(sink, &cvolume, true, true);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *n, *v;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_sink_input *si;
|
2006-01-27 16:25:31 +00:00
|
|
|
pa_volume_t volume;
|
|
|
|
|
pa_cvolume cvolume;
|
2006-01-11 01:17:39 +00:00
|
|
|
uint32_t idx;
|
2004-07-14 21:52:41 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(v = pa_tokenizer_get(t, 2))) {
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
|
2004-07-14 21:52:41 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 00:10:41 +00:00
|
|
|
if (pa_atou(v, &volume) < 0) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse volume.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-09 23:10:00 +05:30
|
|
|
if (!PA_VOLUME_IS_VALID(volume)) {
|
|
|
|
|
pa_strbuf_puts(buf, "Volume outside permissible range.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-14 13:41:06 +02:00
|
|
|
if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink input found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-27 23:00:26 +03:00
|
|
|
if (!si->volume_writable) {
|
2011-02-14 13:41:06 +02:00
|
|
|
pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-31 21:41:36 +02:00
|
|
|
pa_cvolume_set(&cvolume, 1, volume);
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_sink_input_set_volume(si, &cvolume, true, true);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2006-02-22 14:11:23 +00:00
|
|
|
const char *n, *v;
|
|
|
|
|
pa_source *source;
|
|
|
|
|
uint32_t volume;
|
|
|
|
|
pa_cvolume cvolume;
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2006-02-22 14:11:23 +00:00
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(v = pa_tokenizer_get(t, 2))) {
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
|
2006-02-22 14:11:23 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_atou(v, &volume) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse volume.\n");
|
|
|
|
|
return -1;
|
2010-10-09 23:10:00 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!PA_VOLUME_IS_VALID(volume)) {
|
|
|
|
|
pa_strbuf_puts(buf, "Volume outside permissible range.\n");
|
|
|
|
|
return -1;
|
2006-02-22 14:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
|
2006-02-22 14:11:23 +00:00
|
|
|
pa_strbuf_puts(buf, "No source found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-31 21:41:36 +02:00
|
|
|
pa_cvolume_set(&cvolume, 1, volume);
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_source_set_volume(source, &cvolume, true, true);
|
2006-02-22 14:11:23 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_source_output_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2012-04-05 11:52:24 +01:00
|
|
|
const char *n, *v;
|
|
|
|
|
pa_source_output *so;
|
|
|
|
|
pa_volume_t volume;
|
|
|
|
|
pa_cvolume cvolume;
|
|
|
|
|
uint32_t idx;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(v = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_atou(v, &volume) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse volume.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!PA_VOLUME_IS_VALID(volume)) {
|
|
|
|
|
pa_strbuf_puts(buf, "Volume outside permissible range.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(so = pa_idxset_get_by_index(c->source_outputs, idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No source output found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!so->volume_writable) {
|
|
|
|
|
pa_strbuf_puts(buf, "This source output's volume can't be changed.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_cvolume_set(&cvolume, 1, volume);
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_source_output_set_volume(so, &cvolume, true, true);
|
2012-04-05 11:52:24 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2006-02-23 12:04:31 +00:00
|
|
|
const char *n, *m;
|
|
|
|
|
pa_sink *sink;
|
|
|
|
|
int mute;
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2006-02-23 12:04:31 +00:00
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if ((mute = pa_parse_boolean(m)) < 0) {
|
2006-02-23 12:04:31 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
|
2006-02-23 12:04:31 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_sink_set_mute(sink, mute, true);
|
2006-02-23 12:04:31 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2006-02-23 12:04:31 +00:00
|
|
|
const char *n, *m;
|
|
|
|
|
pa_source *source;
|
|
|
|
|
int mute;
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2006-02-23 12:04:31 +00:00
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if ((mute = pa_parse_boolean(m)) < 0) {
|
2006-02-23 12:04:31 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
|
2006-02-23 12:04:31 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_source_set_mute(source, mute, true);
|
2006-02-23 12:04:31 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2008-10-31 18:43:38 +02:00
|
|
|
const char *n, *s;
|
|
|
|
|
pa_sink *sink;
|
|
|
|
|
pa_proplist *p;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(s = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
|
2008-10-31 18:43:38 +02:00
|
|
|
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-30 16:24:18 +02:00
|
|
|
if (!(p = pa_proplist_from_string(s))) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse proplist.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2008-10-31 18:43:38 +02:00
|
|
|
|
|
|
|
|
pa_sink_update_proplist(sink, PA_UPDATE_REPLACE, p);
|
|
|
|
|
|
2009-01-13 19:07:59 +02:00
|
|
|
pa_proplist_free(p);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-01-13 19:07:59 +02:00
|
|
|
const char *n, *s;
|
|
|
|
|
pa_source *source;
|
|
|
|
|
pa_proplist *p;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(s = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
|
2009-01-13 19:07:59 +02:00
|
|
|
pa_strbuf_puts(buf, "No source found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-30 16:24:18 +02:00
|
|
|
if (!(p = pa_proplist_from_string(s))) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse proplist.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2009-01-13 19:07:59 +02:00
|
|
|
|
|
|
|
|
pa_source_update_proplist(source, PA_UPDATE_REPLACE, p);
|
|
|
|
|
|
|
|
|
|
pa_proplist_free(p);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-01-13 19:07:59 +02:00
|
|
|
const char *n, *s;
|
|
|
|
|
pa_sink_input *si;
|
|
|
|
|
uint32_t idx;
|
|
|
|
|
pa_proplist *p;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink input either by index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(s = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No sink input found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-30 16:24:18 +02:00
|
|
|
if (!(p = pa_proplist_from_string(s))) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse proplist.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2009-01-13 19:07:59 +02:00
|
|
|
|
|
|
|
|
pa_sink_input_update_proplist(si, PA_UPDATE_REPLACE, p);
|
|
|
|
|
|
|
|
|
|
pa_proplist_free(p);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-01-13 19:07:59 +02:00
|
|
|
const char *n, *s;
|
|
|
|
|
pa_source_output *so;
|
|
|
|
|
uint32_t idx;
|
|
|
|
|
pa_proplist *p;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(s = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No source output found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-30 16:24:18 +02:00
|
|
|
if (!(p = pa_proplist_from_string(s))) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse proplist.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2009-01-13 19:07:59 +02:00
|
|
|
|
|
|
|
|
pa_source_output_update_proplist(so, PA_UPDATE_REPLACE, p);
|
|
|
|
|
|
|
|
|
|
pa_proplist_free(p);
|
|
|
|
|
|
2008-10-31 18:43:38 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
const char *n, *v;
|
|
|
|
|
pa_sink_input *si;
|
|
|
|
|
uint32_t idx;
|
|
|
|
|
int mute;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(v = pa_tokenizer_get(t, 2))) {
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
|
2007-10-28 19:13:50 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if ((mute = pa_parse_boolean(v)) < 0) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No sink input found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_sink_input_set_mute(si, mute, true);
|
2007-10-28 19:13:50 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_source_output_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2012-04-05 11:52:24 +01:00
|
|
|
const char *n, *v;
|
|
|
|
|
pa_source_output *so;
|
|
|
|
|
uint32_t idx;
|
|
|
|
|
int mute;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(v = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((mute = pa_parse_boolean(v)) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No source output found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_source_output_set_mute(so, mute, true);
|
2012-04-05 11:52:24 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *n;
|
2009-01-28 01:46:27 +01:00
|
|
|
pa_sink *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-28 01:46:27 +01:00
|
|
|
if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK)))
|
improve default sink/source handling
Currently the default sink policy is simple: either the user has
configured it explicitly, in which case we always use that as the
default, or we pick the sink with the highest priority. The sink
priorities are currently static, so there's no need to worry about
updating the default sink when sink priorities change.
I intend to make things a bit more complex: if the active port of a sink
is unavailable, the sink should not be the default sink, and I also want
to make sink priorities dependent on the active port, so changing the
port should cause re-evaluation of which sink to choose as the default.
Currently the default sink choice is done only when someone calls
pa_namereg_get_default_sink(), and change notifications are only sent
when a sink is created or destroyed. That makes it hard to add new rules
to the default sink selection policy.
This patch moves the default sink selection to
pa_core_update_default_sink(), which is called whenever something
happens that can affect the default sink choice. That function needs to
know the previous choice in order to send change notifications as
appropriate, but previously pa_core.default_sink was only set when the
user had configured it explicitly. Now pa_core.default_sink is always
set (unless there are no sinks at all), so pa_core_update_default_sink()
can use that to get the previous choice. The user configuration is saved
in a new variable, pa_core.configured_default_sink.
pa_namereg_get_default_sink() is now unnecessary, because
pa_core.default_sink can be used directly to get the
currently-considered-best sink. pa_namereg_set_default_sink() is
replaced by pa_core_set_configured_default_sink().
I haven't confirmed it, but I expect that this patch will fix problems
in the D-Bus protocol related to default sink handling. The D-Bus
protocol used to get confused when the current default sink gets
removed. It would incorrectly think that if there's no explicitly
configured default sink, then there's no default sink at all. Even
worse, when the D-Bus thinks that there's no default sink, it concludes
that there are no sinks at all, which made it impossible to configure
the default sink via the D-Bus interface. Now that pa_core.default_sink
is always set, except when there really aren't any sinks, the D-Bus
protocol should behave correctly.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99425
2017-02-16 12:09:38 +02:00
|
|
|
pa_core_set_configured_default_sink(c, s);
|
2009-01-28 01:46:27 +01:00
|
|
|
else
|
|
|
|
|
pa_strbuf_printf(buf, "Sink %s does not exist.\n", n);
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *n;
|
2009-01-28 01:46:27 +01:00
|
|
|
pa_source *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-28 01:46:27 +01:00
|
|
|
if ((s = pa_namereg_get(c, n, PA_NAMEREG_SOURCE)))
|
improve default sink/source handling
Currently the default sink policy is simple: either the user has
configured it explicitly, in which case we always use that as the
default, or we pick the sink with the highest priority. The sink
priorities are currently static, so there's no need to worry about
updating the default sink when sink priorities change.
I intend to make things a bit more complex: if the active port of a sink
is unavailable, the sink should not be the default sink, and I also want
to make sink priorities dependent on the active port, so changing the
port should cause re-evaluation of which sink to choose as the default.
Currently the default sink choice is done only when someone calls
pa_namereg_get_default_sink(), and change notifications are only sent
when a sink is created or destroyed. That makes it hard to add new rules
to the default sink selection policy.
This patch moves the default sink selection to
pa_core_update_default_sink(), which is called whenever something
happens that can affect the default sink choice. That function needs to
know the previous choice in order to send change notifications as
appropriate, but previously pa_core.default_sink was only set when the
user had configured it explicitly. Now pa_core.default_sink is always
set (unless there are no sinks at all), so pa_core_update_default_sink()
can use that to get the previous choice. The user configuration is saved
in a new variable, pa_core.configured_default_sink.
pa_namereg_get_default_sink() is now unnecessary, because
pa_core.default_sink can be used directly to get the
currently-considered-best sink. pa_namereg_set_default_sink() is
replaced by pa_core_set_configured_default_sink().
I haven't confirmed it, but I expect that this patch will fix problems
in the D-Bus protocol related to default sink handling. The D-Bus
protocol used to get confused when the current default sink gets
removed. It would incorrectly think that if there's no explicitly
configured default sink, then there's no default sink at all. Even
worse, when the D-Bus thinks that there's no default sink, it concludes
that there are no sinks at all, which made it impossible to configure
the default sink via the D-Bus interface. Now that pa_core.default_sink
is always set, except when there really aren't any sinks, the D-Bus
protocol should behave correctly.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99425
2017-02-16 12:09:38 +02:00
|
|
|
pa_core_set_configured_default_source(c, s);
|
2009-01-28 01:46:27 +01:00
|
|
|
else
|
|
|
|
|
pa_strbuf_printf(buf, "Source %s does not exist.\n", n);
|
2004-07-14 21:52:41 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *n;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_client *client;
|
|
|
|
|
uint32_t idx;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if (!(client = pa_idxset_get_by_index(c->clients, idx))) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "No client found by this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_client_kill(client);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *n;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_sink_input *sink_input;
|
|
|
|
|
uint32_t idx;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink input found by this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_sink_input_kill(sink_input);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *n;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_source_output *source_output;
|
|
|
|
|
uint32_t idx;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-11 01:17:39 +00:00
|
|
|
if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) {
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_strbuf_puts(buf, "No source output found by this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_source_output_kill(source_output);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-20 01:07:06 +00:00
|
|
|
char *s;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
pa_assert_se(s = pa_scache_list_to_string(c));
|
2004-07-20 01:07:06 +00:00
|
|
|
pa_strbuf_puts(buf, s);
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(s);
|
2007-10-28 19:13:50 +00:00
|
|
|
|
2004-07-20 01:07:06 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-20 01:07:06 +00:00
|
|
|
const char *n, *sink_name;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_sink *sink;
|
2008-05-15 23:34:41 +00:00
|
|
|
uint32_t idx;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-20 01:07:06 +00:00
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
|
2004-07-20 01:07:06 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink by that name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM, NULL, &idx) < 0) {
|
2004-07-20 01:07:06 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to play sample.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_strbuf_printf(buf, "Playing on sink input #%i\n", idx);
|
|
|
|
|
|
2004-07-20 01:07:06 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-07-20 01:07:06 +00:00
|
|
|
const char *n;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-07-20 01:07:06 +00:00
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sample name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_scache_remove_item(c, n) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to remove sample.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-08-03 19:26:56 +00:00
|
|
|
const char *fname, *n;
|
2004-09-15 14:05:28 +00:00
|
|
|
int r;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-08-03 19:26:56 +00:00
|
|
|
|
2004-09-14 23:08:39 +00:00
|
|
|
if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
|
2004-08-03 19:26:56 +00:00
|
|
|
pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-15 14:05:28 +00:00
|
|
|
if (strstr(pa_tokenizer_get(t, 0), "lazy"))
|
|
|
|
|
r = pa_scache_add_file_lazy(c, n, fname, NULL);
|
|
|
|
|
else
|
|
|
|
|
r = pa_scache_add_file(c, n, fname, NULL);
|
|
|
|
|
|
|
|
|
|
if (r < 0)
|
2004-08-03 19:26:56 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to load sound file.\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-11-17 00:05:25 +00:00
|
|
|
const char *pname;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-11-17 00:05:25 +00:00
|
|
|
|
|
|
|
|
if (!(pname = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a path name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_scache_add_directory_lazy(c, pname) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to load directory.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2004-08-03 19:26:56 +00:00
|
|
|
const char *fname, *sink_name;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_sink *sink;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-08-03 19:26:56 +00:00
|
|
|
|
|
|
|
|
if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
|
2004-08-03 19:26:56 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink by that name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-27 16:25:31 +00:00
|
|
|
return pa_play_file(sink, fname, NULL);
|
2004-08-03 19:26:56 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2008-08-01 01:56:09 +03:00
|
|
|
pa_shared_dump(c, buf);
|
2004-10-30 01:55:16 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2006-08-18 19:55:18 +00:00
|
|
|
|
|
|
|
|
pa_mempool_vacuum(c->mempool);
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2006-08-18 19:55:18 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2006-07-29 15:07:15 +00:00
|
|
|
const char *n, *k;
|
|
|
|
|
pa_sink_input *si;
|
|
|
|
|
pa_sink *sink;
|
|
|
|
|
uint32_t idx;
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2006-07-29 15:07:15 +00:00
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(k = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No sink input found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK))) {
|
2006-07-29 15:07:15 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
if (pa_sink_input_move_to(si, sink, true) < 0) {
|
2006-07-29 15:07:15 +00:00
|
|
|
pa_strbuf_puts(buf, "Moved failed.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2006-08-03 22:31:35 +00:00
|
|
|
const char *n, *k;
|
|
|
|
|
pa_source_output *so;
|
|
|
|
|
pa_source *source;
|
|
|
|
|
uint32_t idx;
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
2006-08-03 22:31:35 +00:00
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(k = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No source output found with this index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE))) {
|
2006-08-03 22:31:35 +00:00
|
|
|
pa_strbuf_puts(buf, "No source found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
if (pa_source_output_move_to(so, source, true) < 0) {
|
2006-08-03 22:31:35 +00:00
|
|
|
pa_strbuf_puts(buf, "Moved failed.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
const char *n, *m;
|
|
|
|
|
pa_sink *sink;
|
2009-03-04 05:30:28 +01:00
|
|
|
int suspend, r;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if ((suspend = pa_parse_boolean(m)) < 0) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-16 18:24:34 +02:00
|
|
|
pa_log_debug("%s of sink %s requested via CLI.", suspend ? "Suspending" : "Resuming", sink->name);
|
|
|
|
|
|
2009-06-05 19:05:07 +02:00
|
|
|
if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0)
|
2009-03-04 05:30:28 +01:00
|
|
|
pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", pa_strerror(r));
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
const char *n, *m;
|
|
|
|
|
pa_source *source;
|
2009-03-04 05:30:28 +01:00
|
|
|
int suspend, r;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if ((suspend = pa_parse_boolean(m)) < 0) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-15 20:07:13 +01:00
|
|
|
if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_strbuf_puts(buf, "No source found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-16 18:24:34 +02:00
|
|
|
pa_log_debug("%s of source %s requested via CLI.", suspend ? "Suspending" : "Resuming", source->name);
|
|
|
|
|
|
2009-06-05 19:05:07 +02:00
|
|
|
if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0)
|
2009-03-04 05:30:28 +01:00
|
|
|
pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", pa_strerror(r));
|
|
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2007-10-28 19:13:50 +00:00
|
|
|
const char *m;
|
2009-03-04 05:30:28 +01:00
|
|
|
int suspend, r;
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if ((suspend = pa_parse_boolean(m)) < 0) {
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-16 18:24:34 +02:00
|
|
|
pa_log_debug("%s of all sinks and sources requested via CLI.", suspend ? "Suspending" : "Resuming");
|
|
|
|
|
|
2009-06-05 19:05:07 +02:00
|
|
|
if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
|
2009-03-04 05:30:28 +01:00
|
|
|
pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", pa_strerror(r));
|
2007-10-28 19:13:50 +00:00
|
|
|
|
2009-06-05 19:05:07 +02:00
|
|
|
if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
|
2009-03-04 05:30:28 +01:00
|
|
|
pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", pa_strerror(r));
|
2007-10-28 19:13:50 +00:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_log_target(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2012-05-25 10:16:04 +08:00
|
|
|
const char *m;
|
2013-06-19 11:59:08 +08:00
|
|
|
pa_log_target *log_target = NULL;
|
2012-05-25 10:16:04 +08:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 1))) {
|
2013-06-19 11:59:08 +08:00
|
|
|
pa_strbuf_puts(buf, "You need to specify a log target (null|auto|syslog|stderr|file:PATH|newfile:PATH).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 'auto' is actually the effect with 'stderr' */
|
|
|
|
|
if (pa_streq(m, "auto"))
|
|
|
|
|
log_target = pa_log_target_new(PA_LOG_STDERR, NULL);
|
|
|
|
|
else {
|
|
|
|
|
log_target = pa_log_parse_target(m);
|
|
|
|
|
|
|
|
|
|
if (!log_target) {
|
|
|
|
|
pa_strbuf_puts(buf, "Invalid log target.\n");
|
2012-05-25 10:16:04 +08:00
|
|
|
return -1;
|
|
|
|
|
}
|
2013-06-19 11:59:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_log_set_target(log_target) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to set log target.\n");
|
|
|
|
|
pa_log_target_free(log_target);
|
2012-05-25 10:16:04 +08:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-19 11:59:08 +08:00
|
|
|
pa_log_target_free(log_target);
|
|
|
|
|
|
2012-05-25 10:16:04 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2008-10-21 19:14:07 +02:00
|
|
|
const char *m;
|
|
|
|
|
uint32_t level;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse log level.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-21 22:45:56 +01:00
|
|
|
pa_log_set_level(level);
|
2008-10-21 19:14:07 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2008-10-21 19:14:07 +02:00
|
|
|
const char *m;
|
2012-03-29 15:24:02 +03:00
|
|
|
int b;
|
2008-10-21 19:14:07 +02:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a boolean.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((b = pa_parse_boolean(m)) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-21 22:45:56 +01:00
|
|
|
pa_log_set_flags(PA_LOG_PRINT_META, b ? PA_LOG_SET : PA_LOG_UNSET);
|
2008-10-21 19:14:07 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2008-10-21 19:14:07 +02:00
|
|
|
const char *m;
|
2012-03-29 15:24:02 +03:00
|
|
|
int b;
|
2008-10-21 19:14:07 +02:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a boolean.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((b = pa_parse_boolean(m)) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-21 22:45:56 +01:00
|
|
|
pa_log_set_flags(PA_LOG_PRINT_TIME, b ? PA_LOG_SET : PA_LOG_UNSET);
|
2008-10-21 19:14:07 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2008-10-21 19:14:07 +02:00
|
|
|
const char *m;
|
|
|
|
|
uint32_t nframes;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(m = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a backtrace level.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_atou(m, &nframes) < 0 || nframes >= 1000) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse backtrace level.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_log_set_show_backtrace(nframes);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-01-21 01:54:14 +01:00
|
|
|
const char *n, *p;
|
|
|
|
|
pa_card *card;
|
2013-11-20 15:42:26 +02:00
|
|
|
pa_card_profile *profile;
|
2009-01-21 01:54:14 +01:00
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(p = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No card found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-20 15:42:26 +02:00
|
|
|
if (!(profile = pa_hashmap_get(card->profiles, p))) {
|
|
|
|
|
pa_strbuf_printf(buf, "No such profile: %s\n", p);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_card_set_profile(card, profile, true) < 0) {
|
2009-01-21 01:54:14 +01:00
|
|
|
pa_strbuf_printf(buf, "Failed to set card profile to '%s'.\n", p);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-06-17 03:45:14 +02:00
|
|
|
const char *n, *p;
|
|
|
|
|
pa_sink *sink;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(p = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
if (pa_sink_set_port(sink, p, true) < 0) {
|
2009-06-17 03:45:14 +02:00
|
|
|
pa_strbuf_printf(buf, "Failed to set sink port to '%s'.\n", p);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2009-06-17 03:45:14 +02:00
|
|
|
const char *n, *p;
|
|
|
|
|
pa_source *source;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(p = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No source found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
if (pa_source_set_port(source, p, true) < 0) {
|
2009-06-17 03:45:14 +02:00
|
|
|
pa_strbuf_printf(buf, "Failed to set source port to '%s'.\n", p);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-22 20:55:55 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_port_offset(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2012-06-22 20:55:55 +02:00
|
|
|
const char *n, *p, *l;
|
|
|
|
|
pa_device_port *port;
|
|
|
|
|
pa_card *card;
|
|
|
|
|
int32_t offset;
|
|
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
if (!(n = pa_tokenizer_get(t, 1))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(p = pa_tokenizer_get(t, 2))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a port by its name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(l = pa_tokenizer_get(t, 3))) {
|
|
|
|
|
pa_strbuf_puts(buf, "You need to specify a latency offset.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pa_atoi(l, &offset) < 0) {
|
|
|
|
|
pa_strbuf_puts(buf, "Failed to parse the latency offset.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No card found by this name or index.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(port = pa_hashmap_get(card->ports, p))) {
|
|
|
|
|
pa_strbuf_puts(buf, "No port found by this name.\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-27 17:38:42 +02:00
|
|
|
pa_device_port_set_latency_offset(port, offset);
|
2012-06-22 20:55:55 +02:00
|
|
|
|
2009-06-17 03:45:14 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_module *m;
|
2006-02-22 14:11:23 +00:00
|
|
|
pa_sink *sink;
|
|
|
|
|
pa_source *source;
|
2009-01-21 01:54:14 +01:00
|
|
|
pa_card *card;
|
2013-06-27 19:28:09 +02:00
|
|
|
bool nl;
|
2006-01-11 01:17:39 +00:00
|
|
|
uint32_t idx;
|
2004-09-07 17:06:54 +00:00
|
|
|
time_t now;
|
2011-06-23 22:21:03 +02:00
|
|
|
#ifdef HAVE_CTIME_R
|
|
|
|
|
char txt[256];
|
|
|
|
|
#endif
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
2004-09-07 17:06:54 +00:00
|
|
|
|
|
|
|
|
time(&now);
|
|
|
|
|
|
2006-01-10 17:51:06 +00:00
|
|
|
#ifdef HAVE_CTIME_R
|
2004-09-07 17:06:54 +00:00
|
|
|
pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
|
2006-01-10 17:51:06 +00:00
|
|
|
#else
|
|
|
|
|
pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
|
|
|
|
|
#endif
|
2004-09-07 17:06:54 +00:00
|
|
|
|
2009-09-08 23:50:14 +02:00
|
|
|
PA_IDXSET_FOREACH(m, c->modules, idx) {
|
2004-09-07 17:06:54 +00:00
|
|
|
|
2004-09-14 23:08:39 +00:00
|
|
|
pa_strbuf_printf(buf, "load-module %s", m->name);
|
2004-09-07 17:06:54 +00:00
|
|
|
|
|
|
|
|
if (m->argument)
|
|
|
|
|
pa_strbuf_printf(buf, " %s", m->argument);
|
|
|
|
|
|
|
|
|
|
pa_strbuf_puts(buf, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = false;
|
2009-09-08 23:50:14 +02:00
|
|
|
PA_IDXSET_FOREACH(sink, c->sinks, idx) {
|
2006-02-22 14:11:23 +00:00
|
|
|
|
|
|
|
|
if (!nl) {
|
|
|
|
|
pa_strbuf_puts(buf, "\n");
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = true;
|
2006-02-22 14:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, false)));
|
|
|
|
|
pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, false)));
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED));
|
2006-02-22 14:11:23 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = false;
|
2009-09-08 23:50:14 +02:00
|
|
|
PA_IDXSET_FOREACH(source, c->sources, idx) {
|
2004-09-07 17:06:54 +00:00
|
|
|
|
|
|
|
|
if (!nl) {
|
|
|
|
|
pa_strbuf_puts(buf, "\n");
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = true;
|
2004-09-07 17:06:54 +00:00
|
|
|
}
|
2006-01-27 16:25:31 +00:00
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, false)));
|
|
|
|
|
pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, false)));
|
2008-05-15 23:34:41 +00:00
|
|
|
pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(pa_source_get_state(source) == PA_SOURCE_SUSPENDED));
|
2004-09-07 17:06:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = false;
|
2009-09-08 23:50:14 +02:00
|
|
|
PA_IDXSET_FOREACH(card, c->cards, idx) {
|
2009-01-21 01:54:14 +01:00
|
|
|
|
|
|
|
|
if (!nl) {
|
|
|
|
|
pa_strbuf_puts(buf, "\n");
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = true;
|
2009-01-21 01:54:14 +01:00
|
|
|
}
|
|
|
|
|
|
2012-06-08 21:49:10 +03:00
|
|
|
pa_strbuf_printf(buf, "set-card-profile %s %s\n", card->name, card->active_profile->name);
|
2009-01-21 01:54:14 +01:00
|
|
|
}
|
2004-09-07 17:06:54 +00:00
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = false;
|
improve default sink/source handling
Currently the default sink policy is simple: either the user has
configured it explicitly, in which case we always use that as the
default, or we pick the sink with the highest priority. The sink
priorities are currently static, so there's no need to worry about
updating the default sink when sink priorities change.
I intend to make things a bit more complex: if the active port of a sink
is unavailable, the sink should not be the default sink, and I also want
to make sink priorities dependent on the active port, so changing the
port should cause re-evaluation of which sink to choose as the default.
Currently the default sink choice is done only when someone calls
pa_namereg_get_default_sink(), and change notifications are only sent
when a sink is created or destroyed. That makes it hard to add new rules
to the default sink selection policy.
This patch moves the default sink selection to
pa_core_update_default_sink(), which is called whenever something
happens that can affect the default sink choice. That function needs to
know the previous choice in order to send change notifications as
appropriate, but previously pa_core.default_sink was only set when the
user had configured it explicitly. Now pa_core.default_sink is always
set (unless there are no sinks at all), so pa_core_update_default_sink()
can use that to get the previous choice. The user configuration is saved
in a new variable, pa_core.configured_default_sink.
pa_namereg_get_default_sink() is now unnecessary, because
pa_core.default_sink can be used directly to get the
currently-considered-best sink. pa_namereg_set_default_sink() is
replaced by pa_core_set_configured_default_sink().
I haven't confirmed it, but I expect that this patch will fix problems
in the D-Bus protocol related to default sink handling. The D-Bus
protocol used to get confused when the current default sink gets
removed. It would incorrectly think that if there's no explicitly
configured default sink, then there's no default sink at all. Even
worse, when the D-Bus thinks that there's no default sink, it concludes
that there are no sinks at all, which made it impossible to configure
the default sink via the D-Bus interface. Now that pa_core.default_sink
is always set, except when there really aren't any sinks, the D-Bus
protocol should behave correctly.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99425
2017-02-16 12:09:38 +02:00
|
|
|
if (c->default_sink) {
|
2004-09-07 17:06:54 +00:00
|
|
|
if (!nl) {
|
|
|
|
|
pa_strbuf_puts(buf, "\n");
|
2013-06-27 19:28:09 +02:00
|
|
|
nl = true;
|
2004-09-07 17:06:54 +00:00
|
|
|
}
|
2009-09-08 23:50:14 +02:00
|
|
|
|
improve default sink/source handling
Currently the default sink policy is simple: either the user has
configured it explicitly, in which case we always use that as the
default, or we pick the sink with the highest priority. The sink
priorities are currently static, so there's no need to worry about
updating the default sink when sink priorities change.
I intend to make things a bit more complex: if the active port of a sink
is unavailable, the sink should not be the default sink, and I also want
to make sink priorities dependent on the active port, so changing the
port should cause re-evaluation of which sink to choose as the default.
Currently the default sink choice is done only when someone calls
pa_namereg_get_default_sink(), and change notifications are only sent
when a sink is created or destroyed. That makes it hard to add new rules
to the default sink selection policy.
This patch moves the default sink selection to
pa_core_update_default_sink(), which is called whenever something
happens that can affect the default sink choice. That function needs to
know the previous choice in order to send change notifications as
appropriate, but previously pa_core.default_sink was only set when the
user had configured it explicitly. Now pa_core.default_sink is always
set (unless there are no sinks at all), so pa_core_update_default_sink()
can use that to get the previous choice. The user configuration is saved
in a new variable, pa_core.configured_default_sink.
pa_namereg_get_default_sink() is now unnecessary, because
pa_core.default_sink can be used directly to get the
currently-considered-best sink. pa_namereg_set_default_sink() is
replaced by pa_core_set_configured_default_sink().
I haven't confirmed it, but I expect that this patch will fix problems
in the D-Bus protocol related to default sink handling. The D-Bus
protocol used to get confused when the current default sink gets
removed. It would incorrectly think that if there's no explicitly
configured default sink, then there's no default sink at all. Even
worse, when the D-Bus thinks that there's no default sink, it concludes
that there are no sinks at all, which made it impossible to configure
the default sink via the D-Bus interface. Now that pa_core.default_sink
is always set, except when there really aren't any sinks, the D-Bus
protocol should behave correctly.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99425
2017-02-16 12:09:38 +02:00
|
|
|
pa_strbuf_printf(buf, "set-default-sink %s\n", c->default_sink->name);
|
2004-09-07 17:06:54 +00:00
|
|
|
}
|
|
|
|
|
|
improve default sink/source handling
Currently the default sink policy is simple: either the user has
configured it explicitly, in which case we always use that as the
default, or we pick the sink with the highest priority. The sink
priorities are currently static, so there's no need to worry about
updating the default sink when sink priorities change.
I intend to make things a bit more complex: if the active port of a sink
is unavailable, the sink should not be the default sink, and I also want
to make sink priorities dependent on the active port, so changing the
port should cause re-evaluation of which sink to choose as the default.
Currently the default sink choice is done only when someone calls
pa_namereg_get_default_sink(), and change notifications are only sent
when a sink is created or destroyed. That makes it hard to add new rules
to the default sink selection policy.
This patch moves the default sink selection to
pa_core_update_default_sink(), which is called whenever something
happens that can affect the default sink choice. That function needs to
know the previous choice in order to send change notifications as
appropriate, but previously pa_core.default_sink was only set when the
user had configured it explicitly. Now pa_core.default_sink is always
set (unless there are no sinks at all), so pa_core_update_default_sink()
can use that to get the previous choice. The user configuration is saved
in a new variable, pa_core.configured_default_sink.
pa_namereg_get_default_sink() is now unnecessary, because
pa_core.default_sink can be used directly to get the
currently-considered-best sink. pa_namereg_set_default_sink() is
replaced by pa_core_set_configured_default_sink().
I haven't confirmed it, but I expect that this patch will fix problems
in the D-Bus protocol related to default sink handling. The D-Bus
protocol used to get confused when the current default sink gets
removed. It would incorrectly think that if there's no explicitly
configured default sink, then there's no default sink at all. Even
worse, when the D-Bus thinks that there's no default sink, it concludes
that there are no sinks at all, which made it impossible to configure
the default sink via the D-Bus interface. Now that pa_core.default_sink
is always set, except when there really aren't any sinks, the D-Bus
protocol should behave correctly.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99425
2017-02-16 12:09:38 +02:00
|
|
|
if (c->default_source) {
|
2009-09-08 23:50:14 +02:00
|
|
|
if (!nl)
|
2004-09-07 17:06:54 +00:00
|
|
|
pa_strbuf_puts(buf, "\n");
|
2009-09-08 23:50:14 +02:00
|
|
|
|
improve default sink/source handling
Currently the default sink policy is simple: either the user has
configured it explicitly, in which case we always use that as the
default, or we pick the sink with the highest priority. The sink
priorities are currently static, so there's no need to worry about
updating the default sink when sink priorities change.
I intend to make things a bit more complex: if the active port of a sink
is unavailable, the sink should not be the default sink, and I also want
to make sink priorities dependent on the active port, so changing the
port should cause re-evaluation of which sink to choose as the default.
Currently the default sink choice is done only when someone calls
pa_namereg_get_default_sink(), and change notifications are only sent
when a sink is created or destroyed. That makes it hard to add new rules
to the default sink selection policy.
This patch moves the default sink selection to
pa_core_update_default_sink(), which is called whenever something
happens that can affect the default sink choice. That function needs to
know the previous choice in order to send change notifications as
appropriate, but previously pa_core.default_sink was only set when the
user had configured it explicitly. Now pa_core.default_sink is always
set (unless there are no sinks at all), so pa_core_update_default_sink()
can use that to get the previous choice. The user configuration is saved
in a new variable, pa_core.configured_default_sink.
pa_namereg_get_default_sink() is now unnecessary, because
pa_core.default_sink can be used directly to get the
currently-considered-best sink. pa_namereg_set_default_sink() is
replaced by pa_core_set_configured_default_sink().
I haven't confirmed it, but I expect that this patch will fix problems
in the D-Bus protocol related to default sink handling. The D-Bus
protocol used to get confused when the current default sink gets
removed. It would incorrectly think that if there's no explicitly
configured default sink, then there's no default sink at all. Even
worse, when the D-Bus thinks that there's no default sink, it concludes
that there are no sinks at all, which made it impossible to configure
the default sink via the D-Bus interface. Now that pa_core.default_sink
is always set, except when there really aren't any sinks, the D-Bus
protocol should behave correctly.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=99425
2017-02-16 12:09:38 +02:00
|
|
|
pa_strbuf_printf(buf, "set-default-source %s\n", c->default_source->name);
|
2004-09-07 17:06:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_strbuf_puts(buf, "\n### EOF\n");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, bool *fail) {
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_sink *s;
|
|
|
|
|
pa_source *so;
|
|
|
|
|
pa_sink_input *i;
|
|
|
|
|
pa_source_output *o;
|
|
|
|
|
uint32_t s_idx, i_idx;
|
2013-04-03 16:36:43 +03:00
|
|
|
char v_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
|
|
|
|
|
pa_channel_map *map;
|
2011-08-18 11:56:26 +05:30
|
|
|
|
|
|
|
|
pa_core_assert_ref(c);
|
|
|
|
|
pa_assert(t);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
pa_assert(fail);
|
|
|
|
|
|
|
|
|
|
PA_IDXSET_FOREACH(s, c->sinks, s_idx) {
|
2013-04-03 16:36:43 +03:00
|
|
|
map = &s->channel_map;
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "Sink %d: ", s_idx);
|
2013-04-03 16:36:43 +03:00
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"reference = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&s->reference_volume,
|
|
|
|
|
map,
|
|
|
|
|
s->flags & PA_SINK_DECIBEL_VOLUME));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"real = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&s->real_volume,
|
|
|
|
|
&s->channel_map,
|
|
|
|
|
s->flags & PA_SINK_DECIBEL_VOLUME));
|
|
|
|
|
pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &s->soft_volume, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"current_hw = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&s->thread_info.current_hw_volume,
|
|
|
|
|
map,
|
|
|
|
|
s->flags & PA_SINK_DECIBEL_VOLUME));
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(s->save_volume));
|
|
|
|
|
|
|
|
|
|
PA_IDXSET_FOREACH(i, s->inputs, i_idx) {
|
2013-04-03 16:36:43 +03:00
|
|
|
map = &i->channel_map;
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "\tInput %d: ", i_idx);
|
2013-04-03 16:36:43 +03:00
|
|
|
pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"reference_ratio = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->reference_ratio, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"real_ratio = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->real_ratio, map, true));
|
|
|
|
|
pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->soft_volume, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"volume_factor = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &i->volume_factor, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"volume_factor_sink = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&i->volume_factor_sink,
|
|
|
|
|
&i->sink->channel_map,
|
|
|
|
|
true));
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(i->save_volume));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PA_IDXSET_FOREACH(so, c->sources, s_idx) {
|
2013-04-03 16:36:43 +03:00
|
|
|
map = &so->channel_map;
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "Source %d: ", s_idx);
|
2013-04-03 16:36:43 +03:00
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"reference = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&so->reference_volume,
|
|
|
|
|
map,
|
|
|
|
|
so->flags & PA_SOURCE_DECIBEL_VOLUME));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"real = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&so->real_volume,
|
|
|
|
|
map,
|
|
|
|
|
so->flags & PA_SOURCE_DECIBEL_VOLUME));
|
|
|
|
|
pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &so->soft_volume, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"current_hw = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&so->thread_info.current_hw_volume,
|
|
|
|
|
map,
|
|
|
|
|
so->flags & PA_SOURCE_DECIBEL_VOLUME));
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(so->save_volume));
|
|
|
|
|
|
|
|
|
|
PA_IDXSET_FOREACH(o, so->outputs, i_idx) {
|
2013-04-03 16:36:43 +03:00
|
|
|
map = &o->channel_map;
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "\tOutput %d: ", i_idx);
|
2013-04-03 16:36:43 +03:00
|
|
|
pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"reference_ratio = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->reference_ratio, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"real_ratio = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->real_ratio, map, true));
|
|
|
|
|
pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->soft_volume, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"volume_factor = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str, sizeof(v_str), &o->volume_factor, map, true));
|
|
|
|
|
pa_strbuf_printf(buf,
|
|
|
|
|
"volume_factor_source = %s, ",
|
|
|
|
|
pa_cvolume_snprint_verbose(v_str,
|
|
|
|
|
sizeof(v_str),
|
|
|
|
|
&o->volume_factor_source,
|
|
|
|
|
&o->source->channel_map,
|
|
|
|
|
true));
|
2011-08-18 11:56:26 +05:30
|
|
|
pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(o->save_volume));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, bool *fail, int *ifstate) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *cs;
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(c);
|
|
|
|
|
pa_assert(s);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
cs = s+strspn(s, whitespace);
|
|
|
|
|
|
|
|
|
|
if (*cs == '#' || !*cs)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (*cs == '.') {
|
2007-05-26 23:39:33 +00:00
|
|
|
if (!strcmp(cs, META_ELSE)) {
|
|
|
|
|
if (!ifstate || *ifstate == IFSTATE_NONE) {
|
|
|
|
|
pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (*ifstate == IFSTATE_TRUE)
|
|
|
|
|
*ifstate = IFSTATE_FALSE;
|
|
|
|
|
else
|
|
|
|
|
*ifstate = IFSTATE_TRUE;
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (!strcmp(cs, META_ENDIF)) {
|
|
|
|
|
if (!ifstate || *ifstate == IFSTATE_NONE) {
|
|
|
|
|
pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
|
|
|
|
|
return -1;
|
|
|
|
|
} else
|
|
|
|
|
*ifstate = IFSTATE_NONE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (ifstate && *ifstate == IFSTATE_FALSE)
|
|
|
|
|
return 0;
|
|
|
|
|
if (!strcmp(cs, META_FAIL))
|
2013-06-27 19:28:09 +02:00
|
|
|
*fail = true;
|
2007-05-26 23:39:33 +00:00
|
|
|
else if (!strcmp(cs, META_NOFAIL))
|
2013-06-27 19:28:09 +02:00
|
|
|
*fail = false;
|
2004-07-14 21:52:41 +00:00
|
|
|
else {
|
|
|
|
|
size_t l;
|
|
|
|
|
l = strcspn(cs, whitespace);
|
|
|
|
|
|
2007-05-26 23:39:33 +00:00
|
|
|
if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
|
2010-09-04 17:07:23 +01:00
|
|
|
struct stat st;
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *filename = cs+l+strspn(cs+l, whitespace);
|
2010-09-04 17:07:23 +01:00
|
|
|
|
|
|
|
|
if (stat(filename, &st) < 0) {
|
|
|
|
|
pa_log_warn("stat('%s'): %s", filename, pa_cstrerror(errno));
|
2007-10-28 19:13:50 +00:00
|
|
|
if (*fail)
|
|
|
|
|
return -1;
|
2010-09-04 17:07:23 +01:00
|
|
|
} else {
|
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
|
|
|
|
DIR *d;
|
|
|
|
|
|
|
|
|
|
if (!(d = opendir(filename))) {
|
|
|
|
|
pa_log_warn("Failed to read '%s': %s", filename, pa_cstrerror(errno));
|
|
|
|
|
if (*fail)
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
unsigned i, count;
|
|
|
|
|
char **sorted_files;
|
|
|
|
|
struct dirent *de;
|
2013-06-27 19:28:09 +02:00
|
|
|
bool failed = false;
|
2013-06-26 16:13:47 +03:00
|
|
|
pa_dynarray *files = pa_dynarray_new(NULL);
|
2010-09-04 17:07:23 +01:00
|
|
|
|
|
|
|
|
while ((de = readdir(d))) {
|
|
|
|
|
char *extn;
|
|
|
|
|
size_t flen = strlen(de->d_name);
|
|
|
|
|
|
|
|
|
|
if (flen < 4)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
extn = &de->d_name[flen-3];
|
|
|
|
|
if (strncmp(extn, ".pa", 3) == 0)
|
|
|
|
|
pa_dynarray_append(files, pa_sprintf_malloc("%s" PA_PATH_SEP "%s", filename, de->d_name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
closedir(d);
|
|
|
|
|
|
|
|
|
|
count = pa_dynarray_size(files);
|
|
|
|
|
sorted_files = pa_xnew(char*, count);
|
|
|
|
|
for (i = 0; i < count; ++i)
|
|
|
|
|
sorted_files[i] = pa_dynarray_get(files, i);
|
2013-06-26 16:13:47 +03:00
|
|
|
pa_dynarray_free(files);
|
2010-09-04 17:07:23 +01:00
|
|
|
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
|
for (unsigned j = 0; j < count; ++j) {
|
|
|
|
|
if (strcmp(sorted_files[i], sorted_files[j]) < 0) {
|
|
|
|
|
char *tmp = sorted_files[i];
|
|
|
|
|
sorted_files[i] = sorted_files[j];
|
|
|
|
|
sorted_files[j] = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
|
if (!failed) {
|
|
|
|
|
if (pa_cli_command_execute_file(c, sorted_files[i], buf, fail) < 0 && *fail)
|
2013-06-27 19:28:09 +02:00
|
|
|
failed = true;
|
2010-09-04 17:07:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pa_xfree(sorted_files[i]);
|
|
|
|
|
}
|
|
|
|
|
pa_xfree(sorted_files);
|
|
|
|
|
if (failed)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
} else if (pa_cli_command_execute_file(c, filename, buf, fail) < 0 && *fail) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-05-26 23:39:33 +00:00
|
|
|
} else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
|
|
|
|
|
if (!ifstate) {
|
|
|
|
|
pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (*ifstate != IFSTATE_NONE) {
|
|
|
|
|
pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs);
|
|
|
|
|
return -1;
|
|
|
|
|
} else {
|
|
|
|
|
const char *filename = cs+l+strspn(cs+l, whitespace);
|
2013-09-24 19:45:58 -03:00
|
|
|
*ifstate = pa_module_exists(filename) ? IFSTATE_TRUE : IFSTATE_FALSE;
|
2007-05-26 23:39:33 +00:00
|
|
|
}
|
2004-07-14 21:52:41 +00:00
|
|
|
} else {
|
|
|
|
|
pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
|
|
|
|
|
if (*fail) return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const struct command*command;
|
|
|
|
|
int unknown = 1;
|
|
|
|
|
size_t l;
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2007-05-26 23:39:33 +00:00
|
|
|
if (ifstate && *ifstate == IFSTATE_FALSE)
|
2008-10-31 18:43:38 +02:00
|
|
|
return 0;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2007-05-26 23:39:33 +00:00
|
|
|
l = strcspn(cs, whitespace);
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2007-01-04 13:43:45 +00:00
|
|
|
for (command = commands; command->name; command++)
|
2004-07-14 21:52:41 +00:00
|
|
|
if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
|
|
|
|
|
int ret;
|
2006-01-11 01:17:39 +00:00
|
|
|
pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(t);
|
2004-12-11 00:10:41 +00:00
|
|
|
ret = command->proc(c, t, buf, fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
pa_tokenizer_free(t);
|
|
|
|
|
unknown = 0;
|
|
|
|
|
|
|
|
|
|
if (ret < 0 && *fail)
|
|
|
|
|
return -1;
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unknown) {
|
|
|
|
|
pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
|
|
|
|
|
if (*fail)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) {
|
2007-05-26 23:39:33 +00:00
|
|
|
return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
int pa_cli_command_execute_file_stream(pa_core *c, FILE *f, pa_strbuf *buf, bool *fail) {
|
2010-02-25 08:39:42 +02:00
|
|
|
char line[2048];
|
2007-05-26 23:39:33 +00:00
|
|
|
int ifstate = IFSTATE_NONE;
|
2004-07-14 21:52:41 +00:00
|
|
|
int ret = -1;
|
2013-06-27 19:28:09 +02:00
|
|
|
bool _fail = true;
|
2008-05-15 23:34:41 +00:00
|
|
|
|
|
|
|
|
pa_assert(c);
|
|
|
|
|
pa_assert(f);
|
|
|
|
|
pa_assert(buf);
|
|
|
|
|
|
|
|
|
|
if (!fail)
|
|
|
|
|
fail = &_fail;
|
|
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), f)) {
|
|
|
|
|
pa_strip_nl(line);
|
|
|
|
|
|
|
|
|
|
if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail)
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, bool *fail) {
|
2008-05-15 23:34:41 +00:00
|
|
|
FILE *f = NULL;
|
|
|
|
|
int ret = -1;
|
2013-06-27 19:28:09 +02:00
|
|
|
bool _fail = true;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(c);
|
|
|
|
|
pa_assert(fn);
|
|
|
|
|
pa_assert(buf);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if (!fail)
|
|
|
|
|
fail = &_fail;
|
|
|
|
|
|
2009-10-30 04:54:19 +01:00
|
|
|
if (!(f = pa_fopen_cloexec(fn, "r"))) {
|
2006-05-22 15:20:46 +00:00
|
|
|
pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
|
2004-07-14 21:52:41 +00:00
|
|
|
if (!*fail)
|
|
|
|
|
ret = 0;
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-04 17:07:23 +01:00
|
|
|
pa_log_debug("Parsing script '%s'", fn);
|
2008-05-15 23:34:41 +00:00
|
|
|
ret = pa_cli_command_execute_file_stream(c, f, buf, fail);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
if (f)
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-27 19:28:09 +02:00
|
|
|
int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, bool *fail) {
|
2004-07-14 21:52:41 +00:00
|
|
|
const char *p;
|
2007-05-26 23:39:33 +00:00
|
|
|
int ifstate = IFSTATE_NONE;
|
2013-06-27 19:28:09 +02:00
|
|
|
bool _fail = true;
|
2007-05-29 17:24:48 +00:00
|
|
|
|
2007-10-28 19:13:50 +00:00
|
|
|
pa_assert(c);
|
|
|
|
|
pa_assert(s);
|
|
|
|
|
pa_assert(buf);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
2008-05-15 23:34:41 +00:00
|
|
|
if (!fail)
|
|
|
|
|
fail = &_fail;
|
|
|
|
|
|
2004-07-14 21:52:41 +00:00
|
|
|
p = s;
|
|
|
|
|
while (*p) {
|
|
|
|
|
size_t l = strcspn(p, linebreak);
|
2004-08-04 16:39:30 +00:00
|
|
|
char *line = pa_xstrndup(p, l);
|
2007-01-04 13:43:45 +00:00
|
|
|
|
2007-05-26 23:39:33 +00:00
|
|
|
if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) {
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(line);
|
2004-07-14 21:52:41 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2004-08-04 16:39:30 +00:00
|
|
|
pa_xfree(line);
|
2004-07-14 21:52:41 +00:00
|
|
|
|
|
|
|
|
p += l;
|
|
|
|
|
p += strspn(p, linebreak);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|