"Fossies" - the Fresh Open Source Software Archive

Member "pulseaudio-13.0/src/utils/pactl.c" (13 Sep 2019, 69133 Bytes) of package /linux/misc/pulseaudio-13.0.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pactl.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 12.2_vs_13.0.

    1 /***
    2   This file is part of PulseAudio.
    3 
    4   Copyright 2004-2006 Lennart Poettering
    5 
    6   PulseAudio is free software; you can redistribute it and/or modify
    7   it under the terms of the GNU Lesser General Public License as published
    8   by the Free Software Foundation; either version 2.1 of the License,
    9   or (at your option) any later version.
   10 
   11   PulseAudio is distributed in the hope that it will be useful, but
   12   WITHOUT ANY WARRANTY; without even the implied warranty of
   13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   14   General Public License for more details.
   15 
   16   You should have received a copy of the GNU Lesser General Public License
   17   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
   18 ***/
   19 
   20 #ifdef HAVE_CONFIG_H
   21 #include <config.h>
   22 #endif
   23 
   24 #include <signal.h>
   25 #include <string.h>
   26 #include <errno.h>
   27 #include <unistd.h>
   28 #include <assert.h>
   29 #include <stdio.h>
   30 #include <stdlib.h>
   31 #include <getopt.h>
   32 #include <locale.h>
   33 #include <ctype.h>
   34 
   35 #include <sndfile.h>
   36 
   37 #include <pulse/pulseaudio.h>
   38 #include <pulse/ext-device-restore.h>
   39 
   40 #include <pulsecore/i18n.h>
   41 #include <pulsecore/macro.h>
   42 #include <pulsecore/core-util.h>
   43 #include <pulsecore/log.h>
   44 #include <pulsecore/sndfile-util.h>
   45 
   46 static pa_context *context = NULL;
   47 static pa_mainloop_api *mainloop_api = NULL;
   48 
   49 static char
   50     *list_type = NULL,
   51     *sample_name = NULL,
   52     *sink_name = NULL,
   53     *source_name = NULL,
   54     *module_name = NULL,
   55     *module_args = NULL,
   56     *card_name = NULL,
   57     *profile_name = NULL,
   58     *port_name = NULL,
   59     *formats = NULL;
   60 
   61 static uint32_t
   62     sink_input_idx = PA_INVALID_INDEX,
   63     source_output_idx = PA_INVALID_INDEX,
   64     sink_idx = PA_INVALID_INDEX;
   65 
   66 static bool short_list_format = false;
   67 static uint32_t module_index;
   68 static int32_t latency_offset;
   69 static bool suspend;
   70 static pa_cvolume volume;
   71 static enum volume_flags {
   72     VOL_UINT     = 0,
   73     VOL_PERCENT  = 1,
   74     VOL_LINEAR   = 2,
   75     VOL_DECIBEL  = 3,
   76     VOL_ABSOLUTE = 0 << 4,
   77     VOL_RELATIVE = 1 << 4,
   78 } volume_flags;
   79 
   80 static enum mute_flags {
   81     INVALID_MUTE = -1,
   82     UNMUTE = 0,
   83     MUTE = 1,
   84     TOGGLE_MUTE = 2
   85 } mute = INVALID_MUTE;
   86 
   87 static pa_proplist *proplist = NULL;
   88 
   89 static SNDFILE *sndfile = NULL;
   90 static pa_stream *sample_stream = NULL;
   91 static pa_sample_spec sample_spec;
   92 static pa_channel_map channel_map;
   93 static size_t sample_length = 0;
   94 
   95 /* This variable tracks the number of ongoing asynchronous operations. When a
   96  * new operation begins, this is incremented simply with actions++, and when
   97  * an operation finishes, this is decremented with the complete_action()
   98  * function, which shuts down the program if actions reaches zero. */
   99 static int actions = 0;
  100 
  101 static bool nl = false;
  102 
  103 static enum {
  104     NONE,
  105     EXIT,
  106     STAT,
  107     INFO,
  108     UPLOAD_SAMPLE,
  109     PLAY_SAMPLE,
  110     REMOVE_SAMPLE,
  111     LIST,
  112     MOVE_SINK_INPUT,
  113     MOVE_SOURCE_OUTPUT,
  114     LOAD_MODULE,
  115     UNLOAD_MODULE,
  116     SUSPEND_SINK,
  117     SUSPEND_SOURCE,
  118     SET_CARD_PROFILE,
  119     SET_SINK_PORT,
  120     SET_DEFAULT_SINK,
  121     SET_SOURCE_PORT,
  122     SET_DEFAULT_SOURCE,
  123     SET_SINK_VOLUME,
  124     SET_SOURCE_VOLUME,
  125     SET_SINK_INPUT_VOLUME,
  126     SET_SOURCE_OUTPUT_VOLUME,
  127     SET_SINK_MUTE,
  128     SET_SOURCE_MUTE,
  129     SET_SINK_INPUT_MUTE,
  130     SET_SOURCE_OUTPUT_MUTE,
  131     SET_SINK_FORMATS,
  132     SET_PORT_LATENCY_OFFSET,
  133     SUBSCRIBE
  134 } action = NONE;
  135 
  136 static void quit(int ret) {
  137     pa_assert(mainloop_api);
  138     mainloop_api->quit(mainloop_api, ret);
  139 }
  140 
  141 static void context_drain_complete(pa_context *c, void *userdata) {
  142     pa_context_disconnect(c);
  143 }
  144 
  145 static void drain(void) {
  146     pa_operation *o;
  147 
  148     if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
  149         pa_context_disconnect(context);
  150     else
  151         pa_operation_unref(o);
  152 }
  153 
  154 static void complete_action(void) {
  155     pa_assert(actions > 0);
  156 
  157     if (!(--actions))
  158         drain();
  159 }
  160 
  161 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
  162     char s[PA_BYTES_SNPRINT_MAX];
  163     if (!i) {
  164         pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c)));
  165         quit(1);
  166         return;
  167     }
  168 
  169     pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
  170     printf(ngettext("Currently in use: %u block containing %s bytes total.\n",
  171                     "Currently in use: %u blocks containing %s bytes total.\n",
  172                     i->memblock_total),
  173            i->memblock_total, s);
  174 
  175     pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
  176     printf(ngettext("Allocated during whole lifetime: %u block containing %s bytes total.\n",
  177                     "Allocated during whole lifetime: %u blocks containing %s bytes total.\n",
  178                     i->memblock_allocated),
  179            i->memblock_allocated, s);
  180 
  181     pa_bytes_snprint(s, sizeof(s), i->scache_size);
  182     printf(_("Sample cache size: %s\n"), s);
  183 
  184     complete_action();
  185 }
  186 
  187 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
  188     char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
  189 
  190     if (!i) {
  191         pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
  192         quit(1);
  193         return;
  194     }
  195 
  196     printf(_("Server String: %s\n"
  197              "Library Protocol Version: %u\n"
  198              "Server Protocol Version: %u\n"
  199              "Is Local: %s\n"
  200              "Client Index: %u\n"
  201              "Tile Size: %zu\n"),
  202              pa_context_get_server(c),
  203              pa_context_get_protocol_version(c),
  204              pa_context_get_server_protocol_version(c),
  205              pa_yes_no_localised(pa_context_is_local(c)),
  206              pa_context_get_index(c),
  207              pa_context_get_tile_size(c, NULL));
  208 
  209     pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
  210     pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
  211 
  212     printf(_("User Name: %s\n"
  213              "Host Name: %s\n"
  214              "Server Name: %s\n"
  215              "Server Version: %s\n"
  216              "Default Sample Specification: %s\n"
  217              "Default Channel Map: %s\n"
  218              "Default Sink: %s\n"
  219              "Default Source: %s\n"
  220              "Cookie: %04x:%04x\n"),
  221            i->user_name,
  222            i->host_name,
  223            i->server_name,
  224            i->server_version,
  225            ss,
  226            cm,
  227            i->default_sink_name,
  228            i->default_source_name,
  229            i->cookie >> 16,
  230            i->cookie & 0xFFFFU);
  231 
  232     complete_action();
  233 }
  234 
  235 static const char* get_available_str_ynonly(int available) {
  236     switch (available) {
  237         case PA_PORT_AVAILABLE_YES: return ", available";
  238         case PA_PORT_AVAILABLE_NO: return ", not available";
  239     }
  240     return "";
  241 }
  242 
  243 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
  244 
  245     static const char *state_table[] = {
  246         [1+PA_SINK_INVALID_STATE] = "n/a",
  247         [1+PA_SINK_RUNNING] = "RUNNING",
  248         [1+PA_SINK_IDLE] = "IDLE",
  249         [1+PA_SINK_SUSPENDED] = "SUSPENDED"
  250     };
  251 
  252     char
  253         s[PA_SAMPLE_SPEC_SNPRINT_MAX],
  254         cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
  255         v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
  256         cm[PA_CHANNEL_MAP_SNPRINT_MAX],
  257         f[PA_FORMAT_INFO_SNPRINT_MAX];
  258     char *pl;
  259 
  260     if (is_last < 0) {
  261         pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
  262         quit(1);
  263         return;
  264     }
  265 
  266     if (is_last) {
  267         complete_action();
  268         return;
  269     }
  270 
  271     pa_assert(i);
  272 
  273     if (nl && !short_list_format)
  274         printf("\n");
  275     nl = true;
  276 
  277     if (short_list_format) {
  278         printf("%u\t%s\t%s\t%s\t%s\n",
  279                i->index,
  280                i->name,
  281                pa_strnull(i->driver),
  282                pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
  283                state_table[1+i->state]);
  284         return;
  285     }
  286 
  287     printf(_("Sink #%u\n"
  288              "\tState: %s\n"
  289              "\tName: %s\n"
  290              "\tDescription: %s\n"
  291              "\tDriver: %s\n"
  292              "\tSample Specification: %s\n"
  293              "\tChannel Map: %s\n"
  294              "\tOwner Module: %u\n"
  295              "\tMute: %s\n"
  296              "\tVolume: %s\n"
  297              "\t        balance %0.2f\n"
  298              "\tBase Volume: %s\n"
  299              "\tMonitor Source: %s\n"
  300              "\tLatency: %0.0f usec, configured %0.0f usec\n"
  301              "\tFlags: %s%s%s%s%s%s%s\n"
  302              "\tProperties:\n\t\t%s\n"),
  303            i->index,
  304            state_table[1+i->state],
  305            i->name,
  306            pa_strnull(i->description),
  307            pa_strnull(i->driver),
  308            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
  309            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
  310            i->owner_module,
  311            pa_yes_no_localised(i->mute),
  312            pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SINK_DECIBEL_VOLUME),
  313            pa_cvolume_get_balance(&i->volume, &i->channel_map),
  314            pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SINK_DECIBEL_VOLUME),
  315            pa_strnull(i->monitor_source_name),
  316            (double) i->latency, (double) i->configured_latency,
  317            i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
  318            i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
  319            i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
  320            i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
  321            i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
  322            i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
  323            i->flags & PA_SINK_SET_FORMATS ? "SET_FORMATS " : "",
  324            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  325 
  326     pa_xfree(pl);
  327 
  328     if (i->ports) {
  329         pa_sink_port_info **p;
  330 
  331         printf(_("\tPorts:\n"));
  332         for (p = i->ports; *p; p++)
  333             printf("\t\t%s: %s (priority: %u%s)\n", (*p)->name, (*p)->description,
  334                     (*p)->priority, get_available_str_ynonly((*p)->available));
  335     }
  336 
  337     if (i->active_port)
  338         printf(_("\tActive Port: %s\n"),
  339                i->active_port->name);
  340 
  341     if (i->formats) {
  342         uint8_t j;
  343 
  344         printf(_("\tFormats:\n"));
  345         for (j = 0; j < i->n_formats; j++)
  346             printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j]));
  347     }
  348 }
  349 
  350 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
  351 
  352     static const char *state_table[] = {
  353         [1+PA_SOURCE_INVALID_STATE] = "n/a",
  354         [1+PA_SOURCE_RUNNING] = "RUNNING",
  355         [1+PA_SOURCE_IDLE] = "IDLE",
  356         [1+PA_SOURCE_SUSPENDED] = "SUSPENDED"
  357     };
  358 
  359     char
  360         s[PA_SAMPLE_SPEC_SNPRINT_MAX],
  361         cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
  362         v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
  363         cm[PA_CHANNEL_MAP_SNPRINT_MAX],
  364         f[PA_FORMAT_INFO_SNPRINT_MAX];
  365     char *pl;
  366 
  367     if (is_last < 0) {
  368         pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
  369         quit(1);
  370         return;
  371     }
  372 
  373     if (is_last) {
  374         complete_action();
  375         return;
  376     }
  377 
  378     pa_assert(i);
  379 
  380     if (nl && !short_list_format)
  381         printf("\n");
  382     nl = true;
  383 
  384     if (short_list_format) {
  385         printf("%u\t%s\t%s\t%s\t%s\n",
  386                i->index,
  387                i->name,
  388                pa_strnull(i->driver),
  389                pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
  390                state_table[1+i->state]);
  391         return;
  392     }
  393 
  394     printf(_("Source #%u\n"
  395              "\tState: %s\n"
  396              "\tName: %s\n"
  397              "\tDescription: %s\n"
  398              "\tDriver: %s\n"
  399              "\tSample Specification: %s\n"
  400              "\tChannel Map: %s\n"
  401              "\tOwner Module: %u\n"
  402              "\tMute: %s\n"
  403              "\tVolume: %s\n"
  404              "\t        balance %0.2f\n"
  405              "\tBase Volume: %s\n"
  406              "\tMonitor of Sink: %s\n"
  407              "\tLatency: %0.0f usec, configured %0.0f usec\n"
  408              "\tFlags: %s%s%s%s%s%s\n"
  409              "\tProperties:\n\t\t%s\n"),
  410            i->index,
  411            state_table[1+i->state],
  412            i->name,
  413            pa_strnull(i->description),
  414            pa_strnull(i->driver),
  415            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
  416            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
  417            i->owner_module,
  418            pa_yes_no_localised(i->mute),
  419            pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SOURCE_DECIBEL_VOLUME),
  420            pa_cvolume_get_balance(&i->volume, &i->channel_map),
  421            pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SOURCE_DECIBEL_VOLUME),
  422            i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
  423            (double) i->latency, (double) i->configured_latency,
  424            i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
  425            i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
  426            i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
  427            i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
  428            i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
  429            i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
  430            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  431 
  432     pa_xfree(pl);
  433 
  434     if (i->ports) {
  435         pa_source_port_info **p;
  436 
  437         printf(_("\tPorts:\n"));
  438         for (p = i->ports; *p; p++)
  439             printf("\t\t%s: %s (priority: %u%s)\n", (*p)->name, (*p)->description,
  440                     (*p)->priority, get_available_str_ynonly((*p)->available));
  441     }
  442 
  443     if (i->active_port)
  444         printf(_("\tActive Port: %s\n"),
  445                i->active_port->name);
  446 
  447     if (i->formats) {
  448         uint8_t j;
  449 
  450         printf(_("\tFormats:\n"));
  451         for (j = 0; j < i->n_formats; j++)
  452             printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j]));
  453     }
  454 }
  455 
  456 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
  457     char t[32];
  458     char *pl;
  459 
  460     if (is_last < 0) {
  461         pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
  462         quit(1);
  463         return;
  464     }
  465 
  466     if (is_last) {
  467         complete_action();
  468         return;
  469     }
  470 
  471     pa_assert(i);
  472 
  473     if (nl && !short_list_format)
  474         printf("\n");
  475     nl = true;
  476 
  477     pa_snprintf(t, sizeof(t), "%u", i->n_used);
  478 
  479     if (short_list_format) {
  480         printf("%u\t%s\t%s\t\n", i->index, i->name, i->argument ? i->argument : "");
  481         return;
  482     }
  483 
  484     printf(_("Module #%u\n"
  485              "\tName: %s\n"
  486              "\tArgument: %s\n"
  487              "\tUsage counter: %s\n"
  488              "\tProperties:\n\t\t%s\n"),
  489            i->index,
  490            i->name,
  491            i->argument ? i->argument : "",
  492            i->n_used != PA_INVALID_INDEX ? t : _("n/a"),
  493            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  494 
  495     pa_xfree(pl);
  496 }
  497 
  498 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
  499     char t[32];
  500     char *pl;
  501 
  502     if (is_last < 0) {
  503         pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
  504         quit(1);
  505         return;
  506     }
  507 
  508     if (is_last) {
  509         complete_action();
  510         return;
  511     }
  512 
  513     pa_assert(i);
  514 
  515     if (nl && !short_list_format)
  516         printf("\n");
  517     nl = true;
  518 
  519     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
  520 
  521     if (short_list_format) {
  522         printf("%u\t%s\t%s\n",
  523                i->index,
  524                pa_strnull(i->driver),
  525                pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
  526         return;
  527     }
  528 
  529     printf(_("Client #%u\n"
  530              "\tDriver: %s\n"
  531              "\tOwner Module: %s\n"
  532              "\tProperties:\n\t\t%s\n"),
  533            i->index,
  534            pa_strnull(i->driver),
  535            i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
  536            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  537 
  538     pa_xfree(pl);
  539 }
  540 
  541 static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_last, void *userdata) {
  542     char t[32];
  543     char *pl;
  544 
  545     if (is_last < 0) {
  546         pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c)));
  547         complete_action();
  548         return;
  549     }
  550 
  551     if (is_last) {
  552         complete_action();
  553         return;
  554     }
  555 
  556     pa_assert(i);
  557 
  558     if (nl && !short_list_format)
  559         printf("\n");
  560     nl = true;
  561 
  562     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
  563 
  564     if (short_list_format) {
  565         printf("%u\t%s\t%s\n", i->index, i->name, pa_strnull(i->driver));
  566         return;
  567     }
  568 
  569     printf(_("Card #%u\n"
  570              "\tName: %s\n"
  571              "\tDriver: %s\n"
  572              "\tOwner Module: %s\n"
  573              "\tProperties:\n\t\t%s\n"),
  574            i->index,
  575            i->name,
  576            pa_strnull(i->driver),
  577            i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
  578            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  579 
  580     pa_xfree(pl);
  581 
  582     if (i->n_profiles > 0) {
  583         pa_card_profile_info2 **p;
  584 
  585         printf(_("\tProfiles:\n"));
  586         for (p = i->profiles2; *p; p++)
  587             printf(_("\t\t%s: %s (sinks: %u, sources: %u, priority: %u, available: %s)\n"), (*p)->name,
  588                 (*p)->description, (*p)->n_sinks, (*p)->n_sources, (*p)->priority, pa_yes_no_localised((*p)->available));
  589     }
  590 
  591     if (i->active_profile)
  592         printf(_("\tActive Profile: %s\n"),
  593                i->active_profile->name);
  594 
  595     if (i->ports) {
  596         pa_card_port_info **p;
  597 
  598         printf(_("\tPorts:\n"));
  599         for (p = i->ports; *p; p++) {
  600             pa_card_profile_info **pr = (*p)->profiles;
  601             printf("\t\t%s: %s (priority: %u, latency offset: %" PRId64 " usec%s)\n", (*p)->name,
  602                 (*p)->description, (*p)->priority, (*p)->latency_offset,
  603                 get_available_str_ynonly((*p)->available));
  604 
  605             if (!pa_proplist_isempty((*p)->proplist)) {
  606                 printf(_("\t\t\tProperties:\n\t\t\t\t%s\n"), pl = pa_proplist_to_string_sep((*p)->proplist, "\n\t\t\t\t"));
  607                 pa_xfree(pl);
  608             }
  609 
  610             if (pr) {
  611                 printf(_("\t\t\tPart of profile(s): %s"), pa_strnull((*pr)->name));
  612                 pr++;
  613                 while (*pr) {
  614                     printf(", %s", pa_strnull((*pr)->name));
  615                     pr++;
  616                 }
  617                 printf("\n");
  618             }
  619         }
  620     }
  621 }
  622 
  623 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
  624     char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], f[PA_FORMAT_INFO_SNPRINT_MAX];
  625     char *pl;
  626 
  627     if (is_last < 0) {
  628         pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
  629         quit(1);
  630         return;
  631     }
  632 
  633     if (is_last) {
  634         complete_action();
  635         return;
  636     }
  637 
  638     pa_assert(i);
  639 
  640     if (nl && !short_list_format)
  641         printf("\n");
  642     nl = true;
  643 
  644     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
  645     pa_snprintf(k, sizeof(k), "%u", i->client);
  646 
  647     if (short_list_format) {
  648         printf("%u\t%u\t%s\t%s\t%s\n",
  649                i->index,
  650                i->sink,
  651                i->client != PA_INVALID_INDEX ? k : "-",
  652                pa_strnull(i->driver),
  653                pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
  654         return;
  655     }
  656 
  657     printf(_("Sink Input #%u\n"
  658              "\tDriver: %s\n"
  659              "\tOwner Module: %s\n"
  660              "\tClient: %s\n"
  661              "\tSink: %u\n"
  662              "\tSample Specification: %s\n"
  663              "\tChannel Map: %s\n"
  664              "\tFormat: %s\n"
  665              "\tCorked: %s\n"
  666              "\tMute: %s\n"
  667              "\tVolume: %s\n"
  668              "\t        balance %0.2f\n"
  669              "\tBuffer Latency: %0.0f usec\n"
  670              "\tSink Latency: %0.0f usec\n"
  671              "\tResample method: %s\n"
  672              "\tProperties:\n\t\t%s\n"),
  673            i->index,
  674            pa_strnull(i->driver),
  675            i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
  676            i->client != PA_INVALID_INDEX ? k : _("n/a"),
  677            i->sink,
  678            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
  679            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
  680            pa_format_info_snprint(f, sizeof(f), i->format),
  681            pa_yes_no_localised(i->corked),
  682            pa_yes_no_localised(i->mute),
  683            pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
  684            pa_cvolume_get_balance(&i->volume, &i->channel_map),
  685            (double) i->buffer_usec,
  686            (double) i->sink_usec,
  687            i->resample_method ? i->resample_method : _("n/a"),
  688            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  689 
  690     pa_xfree(pl);
  691 }
  692 
  693 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
  694     char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], f[PA_FORMAT_INFO_SNPRINT_MAX];
  695     char *pl;
  696 
  697     if (is_last < 0) {
  698         pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
  699         quit(1);
  700         return;
  701     }
  702 
  703     if (is_last) {
  704         complete_action();
  705         return;
  706     }
  707 
  708     pa_assert(i);
  709 
  710     if (nl && !short_list_format)
  711         printf("\n");
  712     nl = true;
  713 
  714     pa_snprintf(t, sizeof(t), "%u", i->owner_module);
  715     pa_snprintf(k, sizeof(k), "%u", i->client);
  716 
  717     if (short_list_format) {
  718         printf("%u\t%u\t%s\t%s\t%s\n",
  719                i->index,
  720                i->source,
  721                i->client != PA_INVALID_INDEX ? k : "-",
  722                pa_strnull(i->driver),
  723                pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
  724         return;
  725     }
  726 
  727     printf(_("Source Output #%u\n"
  728              "\tDriver: %s\n"
  729              "\tOwner Module: %s\n"
  730              "\tClient: %s\n"
  731              "\tSource: %u\n"
  732              "\tSample Specification: %s\n"
  733              "\tChannel Map: %s\n"
  734              "\tFormat: %s\n"
  735              "\tCorked: %s\n"
  736              "\tMute: %s\n"
  737              "\tVolume: %s\n"
  738              "\t        balance %0.2f\n"
  739              "\tBuffer Latency: %0.0f usec\n"
  740              "\tSource Latency: %0.0f usec\n"
  741              "\tResample method: %s\n"
  742              "\tProperties:\n\t\t%s\n"),
  743            i->index,
  744            pa_strnull(i->driver),
  745            i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
  746            i->client != PA_INVALID_INDEX ? k : _("n/a"),
  747            i->source,
  748            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
  749            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
  750            pa_format_info_snprint(f, sizeof(f), i->format),
  751            pa_yes_no_localised(i->corked),
  752            pa_yes_no_localised(i->mute),
  753            pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
  754            pa_cvolume_get_balance(&i->volume, &i->channel_map),
  755            (double) i->buffer_usec,
  756            (double) i->source_usec,
  757            i->resample_method ? i->resample_method : _("n/a"),
  758            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  759 
  760     pa_xfree(pl);
  761 }
  762 
  763 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
  764     char t[PA_BYTES_SNPRINT_MAX], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
  765     char *pl;
  766 
  767     if (is_last < 0) {
  768         pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
  769         quit(1);
  770         return;
  771     }
  772 
  773     if (is_last) {
  774         complete_action();
  775         return;
  776     }
  777 
  778     pa_assert(i);
  779 
  780     if (nl && !short_list_format)
  781         printf("\n");
  782     nl = true;
  783 
  784     pa_bytes_snprint(t, sizeof(t), i->bytes);
  785 
  786     if (short_list_format) {
  787         printf("%u\t%s\t%s\t%0.3f\n",
  788                i->index,
  789                i->name,
  790                pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "-",
  791                (double) i->duration/1000000.0);
  792         return;
  793     }
  794 
  795     printf(_("Sample #%u\n"
  796              "\tName: %s\n"
  797              "\tSample Specification: %s\n"
  798              "\tChannel Map: %s\n"
  799              "\tVolume: %s\n"
  800              "\t        balance %0.2f\n"
  801              "\tDuration: %0.1fs\n"
  802              "\tSize: %s\n"
  803              "\tLazy: %s\n"
  804              "\tFilename: %s\n"
  805              "\tProperties:\n\t\t%s\n"),
  806            i->index,
  807            i->name,
  808            pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
  809            pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
  810            pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
  811            pa_cvolume_get_balance(&i->volume, &i->channel_map),
  812            (double) i->duration/1000000.0,
  813            t,
  814            pa_yes_no_localised(i->lazy),
  815            i->filename ? i->filename : _("n/a"),
  816            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
  817 
  818     pa_xfree(pl);
  819 }
  820 
  821 static void simple_callback(pa_context *c, int success, void *userdata) {
  822     if (!success) {
  823         pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
  824         quit(1);
  825         return;
  826     }
  827 
  828     complete_action();
  829 }
  830 
  831 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
  832     if (idx == PA_INVALID_INDEX) {
  833         pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
  834         quit(1);
  835         return;
  836     }
  837 
  838     printf("%u\n", idx);
  839 
  840     complete_action();
  841 }
  842 
  843 static void volume_relative_adjust(pa_cvolume *cv) {
  844     pa_assert(volume_flags & VOL_RELATIVE);
  845 
  846     /* Relative volume change is additive in case of UINT or PERCENT
  847      * and multiplicative for LINEAR or DECIBEL */
  848     if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
  849         unsigned i;
  850         for (i = 0; i < cv->channels; i++) {
  851             if (cv->values[i] + volume.values[i] < PA_VOLUME_NORM)
  852                 cv->values[i] = PA_VOLUME_MUTED;
  853             else
  854                 cv->values[i] = cv->values[i] + volume.values[i] - PA_VOLUME_NORM;
  855         }
  856     }
  857     if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL)
  858         pa_sw_cvolume_multiply(cv, cv, &volume);
  859 }
  860 
  861 static void unload_module_by_name_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
  862     static bool unloaded = false;
  863 
  864     if (is_last < 0) {
  865         pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
  866         quit(1);
  867         return;
  868     }
  869 
  870     if (is_last) {
  871         if (unloaded == false)
  872             pa_log(_("Failed to unload module: Module %s not loaded"), module_name);
  873         complete_action();
  874         return;
  875     }
  876 
  877     pa_assert(i);
  878 
  879     if (pa_streq(module_name, i->name)) {
  880         unloaded = true;
  881         actions++;
  882         pa_operation_unref(pa_context_unload_module(c, i->index, simple_callback, NULL));
  883     }
  884 }
  885 
  886 static void fill_volume(pa_cvolume *cv, unsigned supported) {
  887     if (volume.channels == 1) {
  888         pa_cvolume_set(&volume, supported, volume.values[0]);
  889     } else if (volume.channels != supported) {
  890         pa_log(ngettext("Failed to set volume: You tried to set volumes for %d channel, whereas channel(s) supported = %d\n",
  891                         "Failed to set volume: You tried to set volumes for %d channels, whereas channel(s) supported = %d\n",
  892                         volume.channels),
  893                volume.channels, supported);
  894         quit(1);
  895         return;
  896     }
  897 
  898     if (volume_flags & VOL_RELATIVE)
  899         volume_relative_adjust(cv);
  900     else
  901         *cv = volume;
  902 }
  903 
  904 static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
  905     pa_cvolume cv;
  906 
  907     if (is_last < 0) {
  908         pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
  909         quit(1);
  910         return;
  911     }
  912 
  913     if (is_last)
  914         return;
  915 
  916     pa_assert(i);
  917 
  918     cv = i->volume;
  919     fill_volume(&cv, i->channel_map.channels);
  920 
  921     pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
  922 }
  923 
  924 static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
  925     pa_cvolume cv;
  926 
  927     if (is_last < 0) {
  928         pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
  929         quit(1);
  930         return;
  931     }
  932 
  933     if (is_last)
  934         return;
  935 
  936     pa_assert(i);
  937 
  938     cv = i->volume;
  939     fill_volume(&cv, i->channel_map.channels);
  940 
  941     pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
  942 }
  943 
  944 static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
  945     pa_cvolume cv;
  946 
  947     if (is_last < 0) {
  948         pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
  949         quit(1);
  950         return;
  951     }
  952 
  953     if (is_last)
  954         return;
  955 
  956     pa_assert(i);
  957 
  958     cv = i->volume;
  959     fill_volume(&cv, i->channel_map.channels);
  960 
  961     pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
  962 }
  963 
  964 static void get_source_output_volume_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) {
  965     pa_cvolume cv;
  966 
  967     if (is_last < 0) {
  968         pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
  969         quit(1);
  970         return;
  971     }
  972 
  973     if (is_last)
  974         return;
  975 
  976     pa_assert(o);
  977 
  978     cv = o->volume;
  979     fill_volume(&cv, o->channel_map.channels);
  980 
  981     pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL));
  982 }
  983 
  984 static void sink_toggle_mute_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
  985     if (is_last < 0) {
  986         pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
  987         quit(1);
  988         return;
  989     }
  990 
  991     if (is_last)
  992         return;
  993 
  994     pa_assert(i);
  995 
  996     pa_operation_unref(pa_context_set_sink_mute_by_name(c, i->name, !i->mute, simple_callback, NULL));
  997 }
  998 
  999 static void source_toggle_mute_callback(pa_context *c, const pa_source_info *o, int is_last, void *userdata) {
 1000     if (is_last < 0) {
 1001         pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
 1002         quit(1);
 1003         return;
 1004     }
 1005 
 1006     if (is_last)
 1007         return;
 1008 
 1009     pa_assert(o);
 1010 
 1011     pa_operation_unref(pa_context_set_source_mute_by_name(c, o->name, !o->mute, simple_callback, NULL));
 1012 }
 1013 
 1014 static void sink_input_toggle_mute_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
 1015     if (is_last < 0) {
 1016         pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
 1017         quit(1);
 1018         return;
 1019     }
 1020 
 1021     if (is_last)
 1022         return;
 1023 
 1024     pa_assert(i);
 1025 
 1026     pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, !i->mute, simple_callback, NULL));
 1027 }
 1028 
 1029 static void source_output_toggle_mute_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) {
 1030     if (is_last < 0) {
 1031         pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
 1032         quit(1);
 1033         return;
 1034     }
 1035 
 1036     if (is_last)
 1037         return;
 1038 
 1039     pa_assert(o);
 1040 
 1041     pa_operation_unref(pa_context_set_source_output_mute(c, o->index, !o->mute, simple_callback, NULL));
 1042 }
 1043 
 1044 /* PA_MAX_FORMATS is defined in internal.h so we just define a sane value here */
 1045 #define MAX_FORMATS 256
 1046 
 1047 static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) {
 1048     pa_format_info *f_arr[MAX_FORMATS] = { 0, };
 1049     char *format = NULL;
 1050     const char *state = NULL;
 1051     int i = 0;
 1052     pa_operation *o = NULL;
 1053 
 1054     while ((format = pa_split(str, ";", &state))) {
 1055         pa_format_info *f = pa_format_info_from_string(pa_strip(format));
 1056 
 1057         if (!f) {
 1058             pa_log(_("Failed to set format: invalid format string %s"), format);
 1059             goto error;
 1060         }
 1061 
 1062         f_arr[i++] = f;
 1063         pa_xfree(format);
 1064     }
 1065 
 1066     o = pa_ext_device_restore_save_formats(c, PA_DEVICE_TYPE_SINK, sink, i, f_arr, simple_callback, NULL);
 1067     if (o) {
 1068         pa_operation_unref(o);
 1069         actions++;
 1070     }
 1071 
 1072 done:
 1073     if (format)
 1074         pa_xfree(format);
 1075     while (f_arr[i] && i--)
 1076         pa_format_info_free(f_arr[i]);
 1077 
 1078     return;
 1079 
 1080 error:
 1081     while (f_arr[i] && i--)
 1082         pa_format_info_free(f_arr[i]);
 1083     quit(1);
 1084     goto done;
 1085 }
 1086 
 1087 static void stream_state_callback(pa_stream *s, void *userdata) {
 1088     pa_assert(s);
 1089 
 1090     switch (pa_stream_get_state(s)) {
 1091         case PA_STREAM_CREATING:
 1092         case PA_STREAM_READY:
 1093             break;
 1094 
 1095         case PA_STREAM_TERMINATED:
 1096             drain();
 1097             break;
 1098 
 1099         case PA_STREAM_FAILED:
 1100         default:
 1101             pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
 1102             quit(1);
 1103     }
 1104 }
 1105 
 1106 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
 1107     sf_count_t l;
 1108     float *d;
 1109     pa_assert(s && length && sndfile);
 1110 
 1111     d = pa_xmalloc(length);
 1112 
 1113     pa_assert(sample_length >= length);
 1114     l = (sf_count_t) (length/pa_frame_size(&sample_spec));
 1115 
 1116     if ((sf_readf_float(sndfile, d, l)) != l) {
 1117         pa_xfree(d);
 1118         pa_log(_("Premature end of file"));
 1119         quit(1);
 1120         return;
 1121     }
 1122 
 1123     pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
 1124 
 1125     sample_length -= length;
 1126 
 1127     if (sample_length <= 0) {
 1128         pa_stream_set_write_callback(sample_stream, NULL, NULL);
 1129         pa_stream_finish_upload(sample_stream);
 1130     }
 1131 }
 1132 
 1133 static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) {
 1134 
 1135     switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
 1136 
 1137     case PA_SUBSCRIPTION_EVENT_NEW:
 1138         return _("new");
 1139 
 1140     case PA_SUBSCRIPTION_EVENT_CHANGE:
 1141         return _("change");
 1142 
 1143     case PA_SUBSCRIPTION_EVENT_REMOVE:
 1144         return _("remove");
 1145     }
 1146 
 1147     return _("unknown");
 1148 }
 1149 
 1150 static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) {
 1151 
 1152     switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
 1153 
 1154     case PA_SUBSCRIPTION_EVENT_SINK:
 1155         return _("sink");
 1156 
 1157     case PA_SUBSCRIPTION_EVENT_SOURCE:
 1158         return _("source");
 1159 
 1160     case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
 1161         return _("sink-input");
 1162 
 1163     case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
 1164         return _("source-output");
 1165 
 1166     case PA_SUBSCRIPTION_EVENT_MODULE:
 1167         return _("module");
 1168 
 1169     case PA_SUBSCRIPTION_EVENT_CLIENT:
 1170         return _("client");
 1171 
 1172     case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
 1173         return _("sample-cache");
 1174 
 1175     case PA_SUBSCRIPTION_EVENT_SERVER:
 1176         return _("server");
 1177 
 1178     case PA_SUBSCRIPTION_EVENT_CARD:
 1179         return _("card");
 1180     }
 1181 
 1182     return _("unknown");
 1183 }
 1184 
 1185 static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
 1186     pa_assert(c);
 1187 
 1188     printf(_("Event '%s' on %s #%u\n"),
 1189            subscription_event_type_to_string(t),
 1190            subscription_event_facility_to_string(t),
 1191            idx);
 1192     fflush(stdout);
 1193 }
 1194 
 1195 static void context_state_callback(pa_context *c, void *userdata) {
 1196     pa_operation *o = NULL;
 1197 
 1198     pa_assert(c);
 1199 
 1200     switch (pa_context_get_state(c)) {
 1201         case PA_CONTEXT_CONNECTING:
 1202         case PA_CONTEXT_AUTHORIZING:
 1203         case PA_CONTEXT_SETTING_NAME:
 1204             break;
 1205 
 1206         case PA_CONTEXT_READY:
 1207             switch (action) {
 1208                 case STAT:
 1209                     o = pa_context_stat(c, stat_callback, NULL);
 1210                     break;
 1211 
 1212                 case INFO:
 1213                     o = pa_context_get_server_info(c, get_server_info_callback, NULL);
 1214                     break;
 1215 
 1216                 case PLAY_SAMPLE:
 1217                     o = pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL);
 1218                     break;
 1219 
 1220                 case REMOVE_SAMPLE:
 1221                     o = pa_context_remove_sample(c, sample_name, simple_callback, NULL);
 1222                     break;
 1223 
 1224                 case UPLOAD_SAMPLE:
 1225                     sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
 1226                     pa_assert(sample_stream);
 1227 
 1228                     pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
 1229                     pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
 1230                     pa_stream_connect_upload(sample_stream, sample_length);
 1231                     actions++;
 1232                     break;
 1233 
 1234                 case EXIT:
 1235                     o = pa_context_exit_daemon(c, simple_callback, NULL);
 1236                     break;
 1237 
 1238                 case LIST:
 1239                     if (list_type) {
 1240                         if (pa_streq(list_type, "modules"))
 1241                             o = pa_context_get_module_info_list(c, get_module_info_callback, NULL);
 1242                         else if (pa_streq(list_type, "sinks"))
 1243                             o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL);
 1244                         else if (pa_streq(list_type, "sources"))
 1245                             o = pa_context_get_source_info_list(c, get_source_info_callback, NULL);
 1246                         else if (pa_streq(list_type, "sink-inputs"))
 1247                             o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL);
 1248                         else if (pa_streq(list_type, "source-outputs"))
 1249                             o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL);
 1250                         else if (pa_streq(list_type, "clients"))
 1251                             o = pa_context_get_client_info_list(c, get_client_info_callback, NULL);
 1252                         else if (pa_streq(list_type, "samples"))
 1253                             o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL);
 1254                         else if (pa_streq(list_type, "cards"))
 1255                             o = pa_context_get_card_info_list(c, get_card_info_callback, NULL);
 1256                         else
 1257                             pa_assert_not_reached();
 1258                     } else {
 1259                         o = pa_context_get_module_info_list(c, get_module_info_callback, NULL);
 1260                         if (o) {
 1261                             pa_operation_unref(o);
 1262                             actions++;
 1263                         }
 1264 
 1265                         o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL);
 1266                         if (o) {
 1267                             pa_operation_unref(o);
 1268                             actions++;
 1269                         }
 1270 
 1271                         o = pa_context_get_source_info_list(c, get_source_info_callback, NULL);
 1272                         if (o) {
 1273                             pa_operation_unref(o);
 1274                             actions++;
 1275                         }
 1276                         o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL);
 1277                         if (o) {
 1278                             pa_operation_unref(o);
 1279                             actions++;
 1280                         }
 1281 
 1282                         o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL);
 1283                         if (o) {
 1284                             pa_operation_unref(o);
 1285                             actions++;
 1286                         }
 1287 
 1288                         o = pa_context_get_client_info_list(c, get_client_info_callback, NULL);
 1289                         if (o) {
 1290                             pa_operation_unref(o);
 1291                             actions++;
 1292                         }
 1293 
 1294                         o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL);
 1295                         if (o) {
 1296                             pa_operation_unref(o);
 1297                             actions++;
 1298                         }
 1299 
 1300                         o = pa_context_get_card_info_list(c, get_card_info_callback, NULL);
 1301                         if (o) {
 1302                             pa_operation_unref(o);
 1303                             actions++;
 1304                         }
 1305 
 1306                         o = NULL;
 1307                     }
 1308                     break;
 1309 
 1310                 case MOVE_SINK_INPUT:
 1311                     o = pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL);
 1312                     break;
 1313 
 1314                 case MOVE_SOURCE_OUTPUT:
 1315                     o = pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL);
 1316                     break;
 1317 
 1318                 case LOAD_MODULE:
 1319                     o = pa_context_load_module(c, module_name, module_args, index_callback, NULL);
 1320                     break;
 1321 
 1322                 case UNLOAD_MODULE:
 1323                     if (module_name)
 1324                         o = pa_context_get_module_info_list(c, unload_module_by_name_callback, NULL);
 1325                     else
 1326                         o = pa_context_unload_module(c, module_index, simple_callback, NULL);
 1327                     break;
 1328 
 1329                 case SUSPEND_SINK:
 1330                     if (sink_name)
 1331                         o = pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL);
 1332                     else
 1333                         o = pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL);
 1334                     break;
 1335 
 1336                 case SUSPEND_SOURCE:
 1337                     if (source_name)
 1338                         o = pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL);
 1339                     else
 1340                         o = pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL);
 1341                     break;
 1342 
 1343                 case SET_CARD_PROFILE:
 1344                     o = pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL);
 1345                     break;
 1346 
 1347                 case SET_SINK_PORT:
 1348                     o = pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL);
 1349                     break;
 1350 
 1351                 case SET_DEFAULT_SINK:
 1352                     o = pa_context_set_default_sink(c, sink_name, simple_callback, NULL);
 1353                     break;
 1354 
 1355                 case SET_SOURCE_PORT:
 1356                     o = pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL);
 1357                     break;
 1358 
 1359                 case SET_DEFAULT_SOURCE:
 1360                     o = pa_context_set_default_source(c, source_name, simple_callback, NULL);
 1361                     break;
 1362 
 1363                 case SET_SINK_MUTE:
 1364                     if (mute == TOGGLE_MUTE)
 1365                         o = pa_context_get_sink_info_by_name(c, sink_name, sink_toggle_mute_callback, NULL);
 1366                     else
 1367                         o = pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL);
 1368                     break;
 1369 
 1370                 case SET_SOURCE_MUTE:
 1371                     if (mute == TOGGLE_MUTE)
 1372                         o = pa_context_get_source_info_by_name(c, source_name, source_toggle_mute_callback, NULL);
 1373                     else
 1374                         o = pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL);
 1375                     break;
 1376 
 1377                 case SET_SINK_INPUT_MUTE:
 1378                     if (mute == TOGGLE_MUTE)
 1379                         o = pa_context_get_sink_input_info(c, sink_input_idx, sink_input_toggle_mute_callback, NULL);
 1380                     else
 1381                         o = pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL);
 1382                     break;
 1383 
 1384                 case SET_SOURCE_OUTPUT_MUTE:
 1385                     if (mute == TOGGLE_MUTE)
 1386                         o = pa_context_get_source_output_info(c, source_output_idx, source_output_toggle_mute_callback, NULL);
 1387                     else
 1388                         o = pa_context_set_source_output_mute(c, source_output_idx, mute, simple_callback, NULL);
 1389                     break;
 1390 
 1391                 case SET_SINK_VOLUME:
 1392                     o = pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL);
 1393                     break;
 1394 
 1395                 case SET_SOURCE_VOLUME:
 1396                     o = pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL);
 1397                     break;
 1398 
 1399                 case SET_SINK_INPUT_VOLUME:
 1400                     o = pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL);
 1401                     break;
 1402 
 1403                 case SET_SOURCE_OUTPUT_VOLUME:
 1404                     o = pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL);
 1405                     break;
 1406 
 1407                 case SET_SINK_FORMATS:
 1408                     set_sink_formats(c, sink_idx, formats);
 1409                     break;
 1410 
 1411                 case SET_PORT_LATENCY_OFFSET:
 1412                     o = pa_context_set_port_latency_offset(c, card_name, port_name, latency_offset, simple_callback, NULL);
 1413                     break;
 1414 
 1415                 case SUBSCRIBE:
 1416                     pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
 1417 
 1418                     o = pa_context_subscribe(c,
 1419                                              PA_SUBSCRIPTION_MASK_SINK|
 1420                                              PA_SUBSCRIPTION_MASK_SOURCE|
 1421                                              PA_SUBSCRIPTION_MASK_SINK_INPUT|
 1422                                              PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
 1423                                              PA_SUBSCRIPTION_MASK_MODULE|
 1424                                              PA_SUBSCRIPTION_MASK_CLIENT|
 1425                                              PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
 1426                                              PA_SUBSCRIPTION_MASK_SERVER|
 1427                                              PA_SUBSCRIPTION_MASK_CARD,
 1428                                              NULL,
 1429                                              NULL);
 1430                     break;
 1431 
 1432                 default:
 1433                     pa_assert_not_reached();
 1434             }
 1435 
 1436             if (o) {
 1437                 pa_operation_unref(o);
 1438                 actions++;
 1439             }
 1440 
 1441             if (actions == 0) {
 1442                 pa_log("Operation failed: %s", pa_strerror(pa_context_errno(c)));
 1443                 quit(1);
 1444             }
 1445 
 1446             break;
 1447 
 1448         case PA_CONTEXT_TERMINATED:
 1449             quit(0);
 1450             break;
 1451 
 1452         case PA_CONTEXT_FAILED:
 1453         default:
 1454             pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
 1455             quit(1);
 1456     }
 1457 }
 1458 
 1459 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
 1460     pa_log(_("Got SIGINT, exiting."));
 1461     quit(0);
 1462 }
 1463 
 1464 static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) {
 1465     double v;
 1466     char *vs;
 1467     const char *atod_input;
 1468 
 1469     pa_assert(vol_spec);
 1470     pa_assert(vol);
 1471     pa_assert(vol_flags);
 1472 
 1473     vs = pa_xstrdup(vol_spec);
 1474 
 1475     *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;
 1476     if (strchr(vs, '.'))
 1477         *vol_flags |= VOL_LINEAR;
 1478     if (pa_endswith(vs, "%")) {
 1479         *vol_flags |= VOL_PERCENT;
 1480         vs[strlen(vs)-1] = 0;
 1481     }
 1482     if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) {
 1483         *vol_flags |= VOL_DECIBEL;
 1484         vs[strlen(vs)-2] = 0;
 1485     }
 1486 
 1487     atod_input = vs;
 1488 
 1489     if (atod_input[0] == '+')
 1490         atod_input++; /* pa_atod() doesn't accept leading '+', so skip it. */
 1491 
 1492     if (pa_atod(atod_input, &v) < 0) {
 1493         pa_log(_("Invalid volume specification"));
 1494         pa_xfree(vs);
 1495         return -1;
 1496     }
 1497 
 1498     pa_xfree(vs);
 1499 
 1500     if (*vol_flags & VOL_RELATIVE) {
 1501         if ((*vol_flags & 0x0F) == VOL_UINT)
 1502             v += (double) PA_VOLUME_NORM;
 1503         if ((*vol_flags & 0x0F) == VOL_PERCENT)
 1504             v += 100.0;
 1505         if ((*vol_flags & 0x0F) == VOL_LINEAR)
 1506             v += 1.0;
 1507     }
 1508     if ((*vol_flags & 0x0F) == VOL_PERCENT)
 1509         v = v * (double) PA_VOLUME_NORM / 100;
 1510     if ((*vol_flags & 0x0F) == VOL_LINEAR)
 1511         v = pa_sw_volume_from_linear(v);
 1512     if ((*vol_flags & 0x0F) == VOL_DECIBEL)
 1513         v = pa_sw_volume_from_dB(v);
 1514 
 1515     if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) {
 1516         pa_log(_("Volume outside permissible range.\n"));
 1517         return -1;
 1518     }
 1519 
 1520     *vol = (pa_volume_t) v;
 1521 
 1522     return 0;
 1523 }
 1524 
 1525 static int parse_volumes(char *args[], unsigned n) {
 1526     unsigned i;
 1527 
 1528     if (n >= PA_CHANNELS_MAX) {
 1529         pa_log(_("Invalid number of volume specifications.\n"));
 1530         return -1;
 1531     }
 1532 
 1533     volume.channels = n;
 1534     for (i = 0; i < volume.channels; i++) {
 1535         enum volume_flags flags;
 1536 
 1537         if (parse_volume(args[i], &volume.values[i], &flags) < 0)
 1538             return -1;
 1539 
 1540         if (i > 0 && flags != volume_flags) {
 1541             pa_log(_("Inconsistent volume specification.\n"));
 1542             return -1;
 1543         } else
 1544             volume_flags = flags;
 1545     }
 1546 
 1547     return 0;
 1548 }
 1549 
 1550 static enum mute_flags parse_mute(const char *mute_text) {
 1551     int b;
 1552 
 1553     pa_assert(mute_text);
 1554 
 1555     if (pa_streq("toggle", mute_text))
 1556         return TOGGLE_MUTE;
 1557 
 1558     b = pa_parse_boolean(mute_text);
 1559     switch (b) {
 1560         case 0:
 1561             return UNMUTE;
 1562         case 1:
 1563             return MUTE;
 1564         default:
 1565             return INVALID_MUTE;
 1566     }
 1567 }
 1568 
 1569 static void help(const char *argv0) {
 1570 
 1571     printf("%s %s %s\n",    argv0, _("[options]"), "stat");
 1572     printf("%s %s %s\n",    argv0, _("[options]"), "info");
 1573     printf("%s %s %s %s\n", argv0, _("[options]"), "list [short]", _("[TYPE]"));
 1574     printf("%s %s %s\n",    argv0, _("[options]"), "exit");
 1575     printf("%s %s %s %s\n", argv0, _("[options]"), "upload-sample", _("FILENAME [NAME]"));
 1576     printf("%s %s %s %s\n", argv0, _("[options]"), "play-sample ", _("NAME [SINK]"));
 1577     printf("%s %s %s %s\n", argv0, _("[options]"), "remove-sample ", _("NAME"));
 1578     printf("%s %s %s %s\n", argv0, _("[options]"), "load-module ", _("NAME [ARGS ...]"));
 1579     printf("%s %s %s %s\n", argv0, _("[options]"), "unload-module ", _("NAME|#N"));
 1580     printf("%s %s %s %s\n", argv0, _("[options]"), "move-(sink-input|source-output)", _("#N SINK|SOURCE"));
 1581     printf("%s %s %s %s\n", argv0, _("[options]"), "suspend-(sink|source)", _("NAME|#N 1|0"));
 1582     printf("%s %s %s %s\n", argv0, _("[options]"), "set-card-profile ", _("CARD PROFILE"));
 1583     printf("%s %s %s %s\n", argv0, _("[options]"), "set-default-(sink|source)", _("NAME"));
 1584     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-port", _("NAME|#N PORT"));
 1585     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-volume", _("NAME|#N VOLUME [VOLUME ...]"));
 1586     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-volume", _("#N VOLUME [VOLUME ...]"));
 1587     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-mute", _("NAME|#N 1|0|toggle"));
 1588     printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-mute", _("#N 1|0|toggle"));
 1589     printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats", _("#N FORMATS"));
 1590     printf("%s %s %s %s\n", argv0, _("[options]"), "set-port-latency-offset", _("CARD-NAME|CARD-#N PORT OFFSET"));
 1591     printf("%s %s %s\n",    argv0, _("[options]"), "subscribe");
 1592     printf(_("\nThe special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and @DEFAULT_MONITOR@\n"
 1593              "can be used to specify the default sink, source and monitor.\n"));
 1594 
 1595     printf(_("\n"
 1596              "  -h, --help                            Show this help\n"
 1597              "      --version                         Show version\n\n"
 1598              "  -s, --server=SERVER                   The name of the server to connect to\n"
 1599              "  -n, --client-name=NAME                How to call this client on the server\n"));
 1600 }
 1601 
 1602 enum {
 1603     ARG_VERSION = 256
 1604 };
 1605 
 1606 int main(int argc, char *argv[]) {
 1607     pa_mainloop *m = NULL;
 1608     int ret = 1, c;
 1609     char *server = NULL, *bn;
 1610 
 1611     static const struct option long_options[] = {
 1612         {"server",      1, NULL, 's'},
 1613         {"client-name", 1, NULL, 'n'},
 1614         {"version",     0, NULL, ARG_VERSION},
 1615         {"help",        0, NULL, 'h'},
 1616         {NULL,          0, NULL, 0}
 1617     };
 1618 
 1619     setlocale(LC_ALL, "");
 1620 #ifdef ENABLE_NLS
 1621     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
 1622 #endif
 1623 
 1624     bn = pa_path_get_filename(argv[0]);
 1625 
 1626     proplist = pa_proplist_new();
 1627 
 1628     while ((c = getopt_long(argc, argv, "+s:n:h", long_options, NULL)) != -1) {
 1629         switch (c) {
 1630             case 'h' :
 1631                 help(bn);
 1632                 ret = 0;
 1633                 goto quit;
 1634 
 1635             case ARG_VERSION:
 1636                 printf(_("pactl %s\n"
 1637                          "Compiled with libpulse %s\n"
 1638                          "Linked with libpulse %s\n"),
 1639                        PACKAGE_VERSION,
 1640                        pa_get_headers_version(),
 1641                        pa_get_library_version());
 1642                 ret = 0;
 1643                 goto quit;
 1644 
 1645             case 's':
 1646                 pa_xfree(server);
 1647                 server = pa_xstrdup(optarg);
 1648                 break;
 1649 
 1650             case 'n': {
 1651                 char *t;
 1652 
 1653                 if (!(t = pa_locale_to_utf8(optarg)) ||
 1654                     pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
 1655 
 1656                     pa_log(_("Invalid client name '%s'"), t ? t : optarg);
 1657                     pa_xfree(t);
 1658                     goto quit;
 1659                 }
 1660 
 1661                 pa_xfree(t);
 1662                 break;
 1663             }
 1664 
 1665             default:
 1666                 goto quit;
 1667         }
 1668     }
 1669 
 1670     if (optind < argc) {
 1671         if (pa_streq(argv[optind], "stat")) {
 1672             action = STAT;
 1673 
 1674         } else if (pa_streq(argv[optind], "info"))
 1675             action = INFO;
 1676 
 1677         else if (pa_streq(argv[optind], "exit"))
 1678             action = EXIT;
 1679 
 1680         else if (pa_streq(argv[optind], "list")) {
 1681             action = LIST;
 1682 
 1683             for (int i = optind+1; i < argc; i++) {
 1684                 if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
 1685                     pa_streq(argv[i], "sinks")   || pa_streq(argv[i], "sink-inputs") ||
 1686                     pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
 1687                     pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
 1688                     list_type = pa_xstrdup(argv[i]);
 1689                 } else if (pa_streq(argv[i], "short")) {
 1690                     short_list_format = true;
 1691                 } else {
 1692                     pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
 1693                     goto quit;
 1694                 }
 1695             }
 1696 
 1697         } else if (pa_streq(argv[optind], "upload-sample")) {
 1698             struct SF_INFO sfi;
 1699             action = UPLOAD_SAMPLE;
 1700 
 1701             if (optind+1 >= argc) {
 1702                 pa_log(_("Please specify a sample file to load"));
 1703                 goto quit;
 1704             }
 1705 
 1706             if (optind+2 < argc)
 1707                 sample_name = pa_xstrdup(argv[optind+2]);
 1708             else {
 1709                 char *f = pa_path_get_filename(argv[optind+1]);
 1710                 sample_name = pa_xstrndup(f, strcspn(f, "."));
 1711             }
 1712 
 1713             pa_zero(sfi);
 1714             if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
 1715                 pa_log(_("Failed to open sound file."));
 1716                 goto quit;
 1717             }
 1718 
 1719             if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
 1720                 pa_log(_("Failed to determine sample specification from file."));
 1721                 goto quit;
 1722             }
 1723             sample_spec.format = PA_SAMPLE_FLOAT32;
 1724 
 1725             if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
 1726                 if (sample_spec.channels > 2)
 1727                     pa_log(_("Warning: Failed to determine sample specification from file."));
 1728                 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
 1729             }
 1730 
 1731             pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
 1732             sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
 1733 
 1734         } else if (pa_streq(argv[optind], "play-sample")) {
 1735             action = PLAY_SAMPLE;
 1736             if (argc != optind+2 && argc != optind+3) {
 1737                 pa_log(_("You have to specify a sample name to play"));
 1738                 goto quit;
 1739             }
 1740 
 1741             sample_name = pa_xstrdup(argv[optind+1]);
 1742 
 1743             if (optind+2 < argc)
 1744                 sink_name = pa_xstrdup(argv[optind+2]);
 1745 
 1746         } else if (pa_streq(argv[optind], "remove-sample")) {
 1747             action = REMOVE_SAMPLE;
 1748             if (argc != optind+2) {
 1749                 pa_log(_("You have to specify a sample name to remove"));
 1750                 goto quit;
 1751             }
 1752 
 1753             sample_name = pa_xstrdup(argv[optind+1]);
 1754 
 1755         } else if (pa_streq(argv[optind], "move-sink-input")) {
 1756             action = MOVE_SINK_INPUT;
 1757             if (argc != optind+3) {
 1758                 pa_log(_("You have to specify a sink input index and a sink"));
 1759                 goto quit;
 1760             }
 1761 
 1762             sink_input_idx = (uint32_t) atoi(argv[optind+1]);
 1763             sink_name = pa_xstrdup(argv[optind+2]);
 1764 
 1765         } else if (pa_streq(argv[optind], "move-source-output")) {
 1766             action = MOVE_SOURCE_OUTPUT;
 1767             if (argc != optind+3) {
 1768                 pa_log(_("You have to specify a source output index and a source"));
 1769                 goto quit;
 1770             }
 1771 
 1772             source_output_idx = (uint32_t) atoi(argv[optind+1]);
 1773             source_name = pa_xstrdup(argv[optind+2]);
 1774 
 1775         } else if (pa_streq(argv[optind], "load-module")) {
 1776             int i;
 1777             size_t n = 0;
 1778             char *p;
 1779 
 1780             action = LOAD_MODULE;
 1781 
 1782             if (argc <= optind+1) {
 1783                 pa_log(_("You have to specify a module name and arguments."));
 1784                 goto quit;
 1785             }
 1786 
 1787             module_name = argv[optind+1];
 1788 
 1789             for (i = optind+2; i < argc; i++)
 1790                 n += strlen(argv[i])+1;
 1791 
 1792             if (n > 0) {
 1793                 p = module_args = pa_xmalloc(n);
 1794 
 1795                 for (i = optind+2; i < argc; i++)
 1796                     p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
 1797             }
 1798 
 1799         } else if (pa_streq(argv[optind], "unload-module")) {
 1800             action = UNLOAD_MODULE;
 1801 
 1802             if (argc != optind+2) {
 1803                 pa_log(_("You have to specify a module index or name"));
 1804                 goto quit;
 1805             }
 1806 
 1807             if (pa_atou(argv[optind + 1], &module_index) < 0)
 1808                 module_name = argv[optind + 1];
 1809 
 1810         } else if (pa_streq(argv[optind], "suspend-sink")) {
 1811             int b;
 1812 
 1813             action = SUSPEND_SINK;
 1814 
 1815             if (argc > optind+3 || optind+1 >= argc) {
 1816                 pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
 1817                 goto quit;
 1818             }
 1819 
 1820             if ((b = pa_parse_boolean(argv[argc-1])) < 0) {
 1821                 pa_log(_("Invalid suspend specification."));
 1822                 goto quit;
 1823             }
 1824 
 1825             suspend = !!b;
 1826 
 1827             if (argc > optind+2)
 1828                 sink_name = pa_xstrdup(argv[optind+1]);
 1829 
 1830         } else if (pa_streq(argv[optind], "suspend-source")) {
 1831             int b;
 1832 
 1833             action = SUSPEND_SOURCE;
 1834 
 1835             if (argc > optind+3 || optind+1 >= argc) {
 1836                 pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
 1837                 goto quit;
 1838             }
 1839 
 1840             if ((b = pa_parse_boolean(argv[argc-1])) < 0) {
 1841                 pa_log(_("Invalid suspend specification."));
 1842                 goto quit;
 1843             }
 1844 
 1845             suspend = !!b;
 1846 
 1847             if (argc > optind+2)
 1848                 source_name = pa_xstrdup(argv[optind+1]);
 1849         } else if (pa_streq(argv[optind], "set-card-profile")) {
 1850             action = SET_CARD_PROFILE;
 1851 
 1852             if (argc != optind+3) {
 1853                 pa_log(_("You have to specify a card name/index and a profile name"));
 1854                 goto quit;
 1855             }
 1856 
 1857             card_name = pa_xstrdup(argv[optind+1]);
 1858             profile_name = pa_xstrdup(argv[optind+2]);
 1859 
 1860         } else if (pa_streq(argv[optind], "set-sink-port")) {
 1861             action = SET_SINK_PORT;
 1862 
 1863             if (argc != optind+3) {
 1864                 pa_log(_("You have to specify a sink name/index and a port name"));
 1865                 goto quit;
 1866             }
 1867 
 1868             sink_name = pa_xstrdup(argv[optind+1]);
 1869             port_name = pa_xstrdup(argv[optind+2]);
 1870 
 1871         } else if (pa_streq(argv[optind], "set-default-sink")) {
 1872             action = SET_DEFAULT_SINK;
 1873 
 1874             if (argc != optind+2) {
 1875                 pa_log(_("You have to specify a sink name"));
 1876                 goto quit;
 1877             }
 1878 
 1879             sink_name = pa_xstrdup(argv[optind+1]);
 1880 
 1881         } else if (pa_streq(argv[optind], "set-source-port")) {
 1882             action = SET_SOURCE_PORT;
 1883 
 1884             if (argc != optind+3) {
 1885                 pa_log(_("You have to specify a source name/index and a port name"));
 1886                 goto quit;
 1887             }
 1888 
 1889             source_name = pa_xstrdup(argv[optind+1]);
 1890             port_name = pa_xstrdup(argv[optind+2]);
 1891 
 1892         } else if (pa_streq(argv[optind], "set-default-source")) {
 1893             action = SET_DEFAULT_SOURCE;
 1894 
 1895             if (argc != optind+2) {
 1896                 pa_log(_("You have to specify a source name"));
 1897                 goto quit;
 1898             }
 1899 
 1900             source_name = pa_xstrdup(argv[optind+1]);
 1901 
 1902         } else if (pa_streq(argv[optind], "set-sink-volume")) {
 1903             action = SET_SINK_VOLUME;
 1904 
 1905             if (argc < optind+3) {
 1906                 pa_log(_("You have to specify a sink name/index and a volume"));
 1907                 goto quit;
 1908             }
 1909 
 1910             sink_name = pa_xstrdup(argv[optind+1]);
 1911 
 1912             if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
 1913                 goto quit;
 1914 
 1915         } else if (pa_streq(argv[optind], "set-source-volume")) {
 1916             action = SET_SOURCE_VOLUME;
 1917 
 1918             if (argc < optind+3) {
 1919                 pa_log(_("You have to specify a source name/index and a volume"));
 1920                 goto quit;
 1921             }
 1922 
 1923             source_name = pa_xstrdup(argv[optind+1]);
 1924 
 1925             if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
 1926                 goto quit;
 1927 
 1928         } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
 1929             action = SET_SINK_INPUT_VOLUME;
 1930 
 1931             if (argc < optind+3) {
 1932                 pa_log(_("You have to specify a sink input index and a volume"));
 1933                 goto quit;
 1934             }
 1935 
 1936             if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
 1937                 pa_log(_("Invalid sink input index"));
 1938                 goto quit;
 1939             }
 1940 
 1941             if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
 1942                 goto quit;
 1943 
 1944         } else if (pa_streq(argv[optind], "set-source-output-volume")) {
 1945             action = SET_SOURCE_OUTPUT_VOLUME;
 1946 
 1947             if (argc < optind+3) {
 1948                 pa_log(_("You have to specify a source output index and a volume"));
 1949                 goto quit;
 1950             }
 1951 
 1952             if (pa_atou(argv[optind+1], &source_output_idx) < 0) {
 1953                 pa_log(_("Invalid source output index"));
 1954                 goto quit;
 1955             }
 1956 
 1957             if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
 1958                 goto quit;
 1959 
 1960         } else if (pa_streq(argv[optind], "set-sink-mute")) {
 1961             action = SET_SINK_MUTE;
 1962 
 1963             if (argc != optind+3) {
 1964                 pa_log(_("You have to specify a sink name/index and a mute action (0, 1, or 'toggle')"));
 1965                 goto quit;
 1966             }
 1967 
 1968             if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
 1969                 pa_log(_("Invalid mute specification"));
 1970                 goto quit;
 1971             }
 1972 
 1973             sink_name = pa_xstrdup(argv[optind+1]);
 1974 
 1975         } else if (pa_streq(argv[optind], "set-source-mute")) {
 1976             action = SET_SOURCE_MUTE;
 1977 
 1978             if (argc != optind+3) {
 1979                 pa_log(_("You have to specify a source name/index and a mute action (0, 1, or 'toggle')"));
 1980                 goto quit;
 1981             }
 1982 
 1983             if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
 1984                 pa_log(_("Invalid mute specification"));
 1985                 goto quit;
 1986             }
 1987 
 1988             source_name = pa_xstrdup(argv[optind+1]);
 1989 
 1990         } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
 1991             action = SET_SINK_INPUT_MUTE;
 1992 
 1993             if (argc != optind+3) {
 1994                 pa_log(_("You have to specify a sink input index and a mute action (0, 1, or 'toggle')"));
 1995                 goto quit;
 1996             }
 1997 
 1998             if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
 1999                 pa_log(_("Invalid sink input index specification"));
 2000                 goto quit;
 2001             }
 2002 
 2003             if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
 2004                 pa_log(_("Invalid mute specification"));
 2005                 goto quit;
 2006             }
 2007 
 2008         } else if (pa_streq(argv[optind], "set-source-output-mute")) {
 2009             action = SET_SOURCE_OUTPUT_MUTE;
 2010 
 2011             if (argc != optind+3) {
 2012                 pa_log(_("You have to specify a source output index and a mute action (0, 1, or 'toggle')"));
 2013                 goto quit;
 2014             }
 2015 
 2016             if (pa_atou(argv[optind+1], &source_output_idx) < 0) {
 2017                 pa_log(_("Invalid source output index specification"));
 2018                 goto quit;
 2019             }
 2020 
 2021             if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
 2022                 pa_log(_("Invalid mute specification"));
 2023                 goto quit;
 2024             }
 2025 
 2026         } else if (pa_streq(argv[optind], "subscribe"))
 2027 
 2028             action = SUBSCRIBE;
 2029 
 2030         else if (pa_streq(argv[optind], "set-sink-formats")) {
 2031             int32_t tmp;
 2032 
 2033             if (argc != optind+3 || pa_atoi(argv[optind+1], &tmp) < 0) {
 2034                 pa_log(_("You have to specify a sink index and a semicolon-separated list of supported formats"));
 2035                 goto quit;
 2036             }
 2037 
 2038             sink_idx = tmp;
 2039             action = SET_SINK_FORMATS;
 2040             formats = pa_xstrdup(argv[optind+2]);
 2041 
 2042         } else if (pa_streq(argv[optind], "set-port-latency-offset")) {
 2043             action = SET_PORT_LATENCY_OFFSET;
 2044 
 2045             if (argc != optind+4) {
 2046                 pa_log(_("You have to specify a card name/index, a port name and a latency offset"));
 2047                 goto quit;
 2048             }
 2049 
 2050             card_name = pa_xstrdup(argv[optind+1]);
 2051             port_name = pa_xstrdup(argv[optind+2]);
 2052             if (pa_atoi(argv[optind + 3], &latency_offset) < 0) {
 2053                 pa_log(_("Could not parse latency offset"));
 2054                 goto quit;
 2055             }
 2056 
 2057         } else if (pa_streq(argv[optind], "help")) {
 2058             help(bn);
 2059             ret = 0;
 2060             goto quit;
 2061         }
 2062     }
 2063 
 2064     if (action == NONE) {
 2065         pa_log(_("No valid command specified."));
 2066         goto quit;
 2067     }
 2068 
 2069     if (!(m = pa_mainloop_new())) {
 2070         pa_log(_("pa_mainloop_new() failed."));
 2071         goto quit;
 2072     }
 2073 
 2074     mainloop_api = pa_mainloop_get_api(m);
 2075 
 2076     pa_assert_se(pa_signal_init(mainloop_api) == 0);
 2077     pa_signal_new(SIGINT, exit_signal_callback, NULL);
 2078     pa_signal_new(SIGTERM, exit_signal_callback, NULL);
 2079     pa_disable_sigpipe();
 2080 
 2081     if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
 2082         pa_log(_("pa_context_new() failed."));
 2083         goto quit;
 2084     }
 2085 
 2086     pa_context_set_state_callback(context, context_state_callback, NULL);
 2087     if (pa_context_connect(context, server, 0, NULL) < 0) {
 2088         pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
 2089         goto quit;
 2090     }
 2091 
 2092     if (pa_mainloop_run(m, &ret) < 0) {
 2093         pa_log(_("pa_mainloop_run() failed."));
 2094         goto quit;
 2095     }
 2096 
 2097 quit:
 2098     if (sample_stream)
 2099         pa_stream_unref(sample_stream);
 2100 
 2101     if (context)
 2102         pa_context_unref(context);
 2103 
 2104     if (m) {
 2105         pa_signal_done();
 2106         pa_mainloop_free(m);
 2107     }
 2108 
 2109     pa_xfree(server);
 2110     pa_xfree(list_type);
 2111     pa_xfree(sample_name);
 2112     pa_xfree(sink_name);
 2113     pa_xfree(source_name);
 2114     pa_xfree(module_args);
 2115     pa_xfree(card_name);
 2116     pa_xfree(profile_name);
 2117     pa_xfree(port_name);
 2118     pa_xfree(formats);
 2119 
 2120     if (sndfile)
 2121         sf_close(sndfile);
 2122 
 2123     if (proplist)
 2124         pa_proplist_free(proplist);
 2125 
 2126     return ret;
 2127 }