]> code.delx.au - pulseaudio/blobdiff - src/utils/pactl.c
pactl: Fix a copy-paster error
[pulseaudio] / src / utils / pactl.c
index 269dbfa8fe93d0a1bc4ba8355567cbd09da5986f..50f3d88978e50c0baf07ac1f7c0e289054ee1da6 100644 (file)
@@ -5,7 +5,7 @@
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
 
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2 of the License,
+  by the Free Software Foundation; either version 2.1 of the License,
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
   or (at your option) any later version.
 
   PulseAudio is distributed in the hope that it will be useful, but
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <limits.h>
 #include <getopt.h>
 #include <locale.h>
 #include <getopt.h>
 #include <locale.h>
+#include <ctype.h>
 
 #include <sndfile.h>
 
 
 #include <sndfile.h>
 
-#include <pulse/i18n.h>
 #include <pulse/pulseaudio.h>
 #include <pulse/pulseaudio.h>
-#include <pulsecore/core-util.h>
+#include <pulse/ext-device-restore.h>
 
 
-#define BUFSIZE 1024
+#include <pulsecore/i18n.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/log.h>
+#include <pulsecore/sndfile-util.h>
 
 static pa_context *context = NULL;
 static pa_mainloop_api *mainloop_api = NULL;
 
 
 static pa_context *context = NULL;
 static pa_mainloop_api *mainloop_api = NULL;
 
-static char *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL, *module_name = NULL, *module_args = NULL, *card_name = NULL, *profile_name = NULL;
-static uint32_t sink_input_idx = PA_INVALID_INDEX, source_output_idx = PA_INVALID_INDEX;
+static char
+    *list_type = NULL,
+    *sample_name = NULL,
+    *sink_name = NULL,
+    *source_name = NULL,
+    *module_name = NULL,
+    *module_args = NULL,
+    *card_name = NULL,
+    *profile_name = NULL,
+    *port_name = NULL,
+    *formats = NULL;
+
+static uint32_t
+    sink_input_idx = PA_INVALID_INDEX,
+    source_output_idx = PA_INVALID_INDEX,
+    sink_idx = PA_INVALID_INDEX;
+
+static bool short_list_format = false;
 static uint32_t module_index;
 static uint32_t module_index;
-static int suspend;
+static int32_t latency_offset;
+static bool suspend;
+static pa_volume_t volume;
+static enum volume_flags {
+    VOL_UINT     = 0,
+    VOL_PERCENT  = 1,
+    VOL_LINEAR   = 2,
+    VOL_DECIBEL  = 3,
+    VOL_ABSOLUTE = 0 << 4,
+    VOL_RELATIVE = 1 << 4,
+} volume_flags;
+
+static enum mute_flags {
+    INVALID_MUTE = -1,
+    UNMUTE = 0,
+    MUTE = 1,
+    TOGGLE_MUTE = 2
+} mute = INVALID_MUTE;
+
+static pa_proplist *proplist = NULL;
 
 static SNDFILE *sndfile = NULL;
 static pa_stream *sample_stream = NULL;
 static pa_sample_spec sample_spec;
 
 static SNDFILE *sndfile = NULL;
 static pa_stream *sample_stream = NULL;
 static pa_sample_spec sample_spec;
+static pa_channel_map channel_map;
 static size_t sample_length = 0;
 static size_t sample_length = 0;
-
 static int actions = 1;
 
 static int actions = 1;
 
-static int nl = 0;
+static bool nl = false;
 
 static enum {
     NONE,
     EXIT,
     STAT,
 
 static enum {
     NONE,
     EXIT,
     STAT,
+    INFO,
     UPLOAD_SAMPLE,
     PLAY_SAMPLE,
     REMOVE_SAMPLE,
     UPLOAD_SAMPLE,
     PLAY_SAMPLE,
     REMOVE_SAMPLE,
@@ -73,39 +112,53 @@ static enum {
     UNLOAD_MODULE,
     SUSPEND_SINK,
     SUSPEND_SOURCE,
     UNLOAD_MODULE,
     SUSPEND_SINK,
     SUSPEND_SOURCE,
-    SET_CARD_PROFILE
+    SET_CARD_PROFILE,
+    SET_SINK_PORT,
+    SET_DEFAULT_SINK,
+    SET_SOURCE_PORT,
+    SET_DEFAULT_SOURCE,
+    SET_SINK_VOLUME,
+    SET_SOURCE_VOLUME,
+    SET_SINK_INPUT_VOLUME,
+    SET_SOURCE_OUTPUT_VOLUME,
+    SET_SINK_MUTE,
+    SET_SOURCE_MUTE,
+    SET_SINK_INPUT_MUTE,
+    SET_SOURCE_OUTPUT_MUTE,
+    SET_SINK_FORMATS,
+    SET_PORT_LATENCY_OFFSET,
+    SUBSCRIBE
 } action = NONE;
 
 static void quit(int ret) {
 } action = NONE;
 
 static void quit(int ret) {
-    assert(mainloop_api);
+    pa_assert(mainloop_api);
     mainloop_api->quit(mainloop_api, ret);
 }
 
     mainloop_api->quit(mainloop_api, ret);
 }
 
-
 static void context_drain_complete(pa_context *c, void *userdata) {
     pa_context_disconnect(c);
 }
 
 static void drain(void) {
     pa_operation *o;
 static void context_drain_complete(pa_context *c, void *userdata) {
     pa_context_disconnect(c);
 }
 
 static void drain(void) {
     pa_operation *o;
+
     if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
         pa_context_disconnect(context);
     else
         pa_operation_unref(o);
 }
 
     if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
         pa_context_disconnect(context);
     else
         pa_operation_unref(o);
 }
 
-
 static void complete_action(void) {
 static void complete_action(void) {
-    assert(actions > 0);
+    pa_assert(actions > 0);
 
     if (!(--actions))
         drain();
 }
 
 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
 
     if (!(--actions))
         drain();
 }
 
 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
-    char s[128];
+    char s[PA_BYTES_SNPRINT_MAX];
     if (!i) {
     if (!i) {
-        fprintf(stderr, _("Failed to get statistics: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -126,15 +179,28 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi
     char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
 
     if (!i) {
     char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
 
     if (!i) {
-        fprintf(stderr, _("Failed to get server information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
 
         quit(1);
         return;
     }
 
+    printf(_("Server String: %s\n"
+             "Library Protocol Version: %u\n"
+             "Server Protocol Version: %u\n"
+             "Is Local: %s\n"
+             "Client Index: %u\n"
+             "Tile Size: %zu\n"),
+             pa_context_get_server(c),
+             pa_context_get_protocol_version(c),
+             pa_context_get_server_protocol_version(c),
+             pa_yes_no(pa_context_is_local(c)),
+             pa_context_get_index(c),
+             pa_context_get_tile_size(c, NULL));
+
     pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
     pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
 
     pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
     pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
 
-    printf(_("User name: %s\n"
+    printf(_("User Name: %s\n"
              "Host Name: %s\n"
              "Server Name: %s\n"
              "Server Version: %s\n"
              "Host Name: %s\n"
              "Server Name: %s\n"
              "Server Version: %s\n"
@@ -142,7 +208,7 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi
              "Default Channel Map: %s\n"
              "Default Sink: %s\n"
              "Default Source: %s\n"
              "Default Channel Map: %s\n"
              "Default Sink: %s\n"
              "Default Source: %s\n"
-             "Cookie: %08x\n"),
+             "Cookie: %04x:%04x\n"),
            i->user_name,
            i->host_name,
            i->server_name,
            i->user_name,
            i->host_name,
            i->server_name,
@@ -151,11 +217,20 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi
            cm,
            i->default_sink_name,
            i->default_source_name,
            cm,
            i->default_sink_name,
            i->default_source_name,
-           i->cookie);
+           i->cookie >> 16,
+           i->cookie & 0xFFFFU);
 
     complete_action();
 }
 
 
     complete_action();
 }
 
+static const char* get_available_str_ynonly(int available) {
+    switch (available) {
+        case PA_PORT_AVAILABLE_YES: return ", available";
+        case PA_PORT_AVAILABLE_NO: return ", not available";
+    }
+    return "";
+}
+
 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
 
     static const char *state_table[] = {
 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
 
     static const char *state_table[] = {
@@ -167,15 +242,14 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
 
     char
         s[PA_SAMPLE_SPEC_SNPRINT_MAX],
 
     char
         s[PA_SAMPLE_SPEC_SNPRINT_MAX],
-        cv[PA_CVOLUME_SNPRINT_MAX],
-        cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
-        v[PA_VOLUME_SNPRINT_MAX],
-        vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
-        cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+        cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
+        v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
+        cm[PA_CHANNEL_MAP_SNPRINT_MAX],
+        f[PA_FORMAT_INFO_SNPRINT_MAX];
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get sink information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -185,11 +259,21 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
+    nl = true;
+
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t%s\t%s\n",
+               i->index,
+               i->name,
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
+               state_table[1+i->state]);
+        return;
+    }
 
     printf(_("Sink #%u\n"
              "\tState: %s\n"
 
     printf(_("Sink #%u\n"
              "\tState: %s\n"
@@ -200,12 +284,12 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
              "\tChannel Map: %s\n"
              "\tOwner Module: %u\n"
              "\tMute: %s\n"
              "\tChannel Map: %s\n"
              "\tOwner Module: %u\n"
              "\tMute: %s\n"
-             "\tVolume: %s%s%s\n"
+             "\tVolume: %s\n"
              "\t        balance %0.2f\n"
              "\t        balance %0.2f\n"
-             "\tBase Volume: %s%s%s\n"
+             "\tBase Volume: %s\n"
              "\tMonitor Source: %s\n"
              "\tLatency: %0.0f usec, configured %0.0f usec\n"
              "\tMonitor Source: %s\n"
              "\tLatency: %0.0f usec, configured %0.0f usec\n"
-             "\tFlags: %s%s%s%s%s%s\n"
+             "\tFlags: %s%s%s%s%s%s%s\n"
              "\tProperties:\n\t\t%s\n"),
            i->index,
            state_table[1+i->state],
              "\tProperties:\n\t\t%s\n"),
            i->index,
            state_table[1+i->state],
@@ -216,13 +300,9 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
            i->owner_module,
            pa_yes_no(i->mute),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
            i->owner_module,
            pa_yes_no(i->mute),
-           pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
-           i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t        " : "",
-           i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
+           pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SINK_DECIBEL_VOLUME),
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
-           pa_volume_snprint(v, sizeof(v), i->base_volume),
-           i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t             " : "",
-           i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
+           pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SINK_DECIBEL_VOLUME),
            pa_strnull(i->monitor_source_name),
            (double) i->latency, (double) i->configured_latency,
            i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
            pa_strnull(i->monitor_source_name),
            (double) i->latency, (double) i->configured_latency,
            i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
@@ -231,9 +311,31 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
            i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
            i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
            i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
            i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
            i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
            i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
+           i->flags & PA_SINK_SET_FORMATS ? "SET_FORMATS " : "",
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
 
     pa_xfree(pl);
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
 
     pa_xfree(pl);
+
+    if (i->ports) {
+        pa_sink_port_info **p;
+
+        printf(_("\tPorts:\n"));
+        for (p = i->ports; *p; p++)
+            printf("\t\t%s: %s (priority: %u%s)\n", (*p)->name, (*p)->description,
+                    (*p)->priority, get_available_str_ynonly((*p)->available));
+    }
+
+    if (i->active_port)
+        printf(_("\tActive Port: %s\n"),
+               i->active_port->name);
+
+    if (i->formats) {
+        uint8_t j;
+
+        printf(_("\tFormats:\n"));
+        for (j = 0; j < i->n_formats; j++)
+            printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j]));
+    }
 }
 
 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
 }
 
 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
@@ -247,15 +349,14 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
 
     char
         s[PA_SAMPLE_SPEC_SNPRINT_MAX],
 
     char
         s[PA_SAMPLE_SPEC_SNPRINT_MAX],
-        cv[PA_CVOLUME_SNPRINT_MAX],
-        cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
-        v[PA_VOLUME_SNPRINT_MAX],
-        vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
-        cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+        cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
+        v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
+        cm[PA_CHANNEL_MAP_SNPRINT_MAX],
+        f[PA_FORMAT_INFO_SNPRINT_MAX];
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get source information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -265,11 +366,21 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
+    nl = true;
+
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t%s\t%s\n",
+               i->index,
+               i->name,
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
+               state_table[1+i->state]);
+        return;
+    }
 
     printf(_("Source #%u\n"
              "\tState: %s\n"
 
     printf(_("Source #%u\n"
              "\tState: %s\n"
@@ -280,9 +391,9 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
              "\tChannel Map: %s\n"
              "\tOwner Module: %u\n"
              "\tMute: %s\n"
              "\tChannel Map: %s\n"
              "\tOwner Module: %u\n"
              "\tMute: %s\n"
-             "\tVolume: %s%s%s\n"
+             "\tVolume: %s\n"
              "\t        balance %0.2f\n"
              "\t        balance %0.2f\n"
-             "\tBase Volume: %s%s%s\n"
+             "\tBase Volume: %s\n"
              "\tMonitor of Sink: %s\n"
              "\tLatency: %0.0f usec, configured %0.0f usec\n"
              "\tFlags: %s%s%s%s%s%s\n"
              "\tMonitor of Sink: %s\n"
              "\tLatency: %0.0f usec, configured %0.0f usec\n"
              "\tFlags: %s%s%s%s%s%s\n"
@@ -296,13 +407,9 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
            i->owner_module,
            pa_yes_no(i->mute),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
            i->owner_module,
            pa_yes_no(i->mute),
-           pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
-           i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t        " : "",
-           i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
+           pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SOURCE_DECIBEL_VOLUME),
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
-           pa_volume_snprint(v, sizeof(v), i->base_volume),
-           i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t             " : "",
-           i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
+           pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SOURCE_DECIBEL_VOLUME),
            i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
            (double) i->latency, (double) i->configured_latency,
            i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
            i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
            (double) i->latency, (double) i->configured_latency,
            i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
@@ -314,6 +421,27 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
 
     pa_xfree(pl);
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
 
     pa_xfree(pl);
+
+    if (i->ports) {
+        pa_source_port_info **p;
+
+        printf(_("\tPorts:\n"));
+        for (p = i->ports; *p; p++)
+            printf("\t\t%s: %s (priority: %u%s)\n", (*p)->name, (*p)->description,
+                    (*p)->priority, get_available_str_ynonly((*p)->available));
+    }
+
+    if (i->active_port)
+        printf(_("\tActive Port: %s\n"),
+               i->active_port->name);
+
+    if (i->formats) {
+        uint8_t j;
+
+        printf(_("\tFormats:\n"));
+        for (j = 0; j < i->n_formats; j++)
+            printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j]));
+    }
 }
 
 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
 }
 
 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
@@ -321,7 +449,7 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get module information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -331,13 +459,18 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
+    nl = true;
 
 
-    snprintf(t, sizeof(t), "%u", i->n_used);
+    pa_snprintf(t, sizeof(t), "%u", i->n_used);
+
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t\n", i->index, i->name, i->argument ? i->argument : "");
+        return;
+    }
 
     printf(_("Module #%u\n"
              "\tName: %s\n"
 
     printf(_("Module #%u\n"
              "\tName: %s\n"
@@ -358,7 +491,7 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get client information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -368,13 +501,21 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
+    nl = true;
 
 
-    snprintf(t, sizeof(t), "%u", i->owner_module);
+    pa_snprintf(t, sizeof(t), "%u", i->owner_module);
+
+    if (short_list_format) {
+        printf("%u\t%s\t%s\n",
+               i->index,
+               pa_strnull(i->driver),
+               pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
+        return;
+    }
 
     printf(_("Client #%u\n"
              "\tDriver: %s\n"
 
     printf(_("Client #%u\n"
              "\tDriver: %s\n"
@@ -393,7 +534,7 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get card information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c)));
         complete_action();
         return;
     }
         complete_action();
         return;
     }
@@ -403,13 +544,18 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
+    nl = true;
 
 
-    snprintf(t, sizeof(t), "%u", i->owner_module);
+    pa_snprintf(t, sizeof(t), "%u", i->owner_module);
+
+    if (short_list_format) {
+        printf("%u\t%s\t%s\n", i->index, i->name, pa_strnull(i->driver));
+        return;
+    }
 
     printf(_("Card #%u\n"
              "\tName: %s\n"
 
     printf(_("Card #%u\n"
              "\tName: %s\n"
@@ -422,27 +568,55 @@ static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_
            i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
 
            i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
 
-    if (i->profiles) {
-        pa_card_profile_info *p;
+    pa_xfree(pl);
+
+    if (i->n_profiles > 0) {
+        pa_card_profile_info2 **p;
 
         printf(_("\tProfiles:\n"));
 
         printf(_("\tProfiles:\n"));
-        for (p = i->profiles; p->name; p++)
-            printf("\t\t%s: %s (sinks: %u, sources: %u, priority. %u)\n", p->name, p->description, p->n_sinks, p->n_sources, p->priority);
+        for (p = i->profiles2; *p; p++)
+            printf("\t\t%s: %s (sinks: %u, sources: %u, priority: %u, available: %s)\n", (*p)->name,
+                (*p)->description, (*p)->n_sinks, (*p)->n_sources, (*p)->priority, pa_yes_no((*p)->available));
     }
 
     if (i->active_profile)
         printf(_("\tActive Profile: %s\n"),
                i->active_profile->name);
 
     }
 
     if (i->active_profile)
         printf(_("\tActive Profile: %s\n"),
                i->active_profile->name);
 
-    pa_xfree(pl);
+    if (i->ports) {
+        pa_card_port_info **p;
+
+        printf(_("\tPorts:\n"));
+        for (p = i->ports; *p; p++) {
+            pa_card_profile_info **pr = (*p)->profiles;
+            printf("\t\t%s: %s (priority: %u, latency offset: %" PRId64 " usec%s)\n", (*p)->name,
+                (*p)->description, (*p)->priority, (*p)->latency_offset,
+                get_available_str_ynonly((*p)->available));
+
+            if (!pa_proplist_isempty((*p)->proplist)) {
+                printf(_("\t\t\tProperties:\n\t\t\t\t%s\n"), pl = pa_proplist_to_string_sep((*p)->proplist, "\n\t\t\t\t"));
+                pa_xfree(pl);
+            }
+
+            if (pr) {
+                printf(_("\t\t\tPart of profile(s): %s"), pa_strnull((*pr)->name));
+                pr++;
+                while (*pr) {
+                    printf(", %s", pa_strnull((*pr)->name));
+                    pr++;
+                }
+                printf("\n");
+            }
+        }
+    }
 }
 
 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
 }
 
 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
-    char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+    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];
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get sink input information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -452,14 +626,24 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
-
-    snprintf(t, sizeof(t), "%u", i->owner_module);
-    snprintf(k, sizeof(k), "%u", i->client);
+    nl = true;
+
+    pa_snprintf(t, sizeof(t), "%u", i->owner_module);
+    pa_snprintf(k, sizeof(k), "%u", i->client);
+
+    if (short_list_format) {
+        printf("%u\t%u\t%s\t%s\t%s\n",
+               i->index,
+               i->sink,
+               i->client != PA_INVALID_INDEX ? k : "-",
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
+        return;
+    }
 
     printf(_("Sink Input #%u\n"
              "\tDriver: %s\n"
 
     printf(_("Sink Input #%u\n"
              "\tDriver: %s\n"
@@ -468,9 +652,10 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info
              "\tSink: %u\n"
              "\tSample Specification: %s\n"
              "\tChannel Map: %s\n"
              "\tSink: %u\n"
              "\tSample Specification: %s\n"
              "\tChannel Map: %s\n"
+             "\tFormat: %s\n"
+             "\tCorked: %s\n"
              "\tMute: %s\n"
              "\tVolume: %s\n"
              "\tMute: %s\n"
              "\tVolume: %s\n"
-             "\t        %s\n"
              "\t        balance %0.2f\n"
              "\tBuffer Latency: %0.0f usec\n"
              "\tSink Latency: %0.0f usec\n"
              "\t        balance %0.2f\n"
              "\tBuffer Latency: %0.0f usec\n"
              "\tSink Latency: %0.0f usec\n"
@@ -483,9 +668,10 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info
            i->sink,
            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
            i->sink,
            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
+           pa_format_info_snprint(f, sizeof(f), i->format),
+           pa_yes_no(i->corked),
            pa_yes_no(i->mute),
            pa_yes_no(i->mute),
-           pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
-           pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
+           pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
            (double) i->buffer_usec,
            (double) i->sink_usec,
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
            (double) i->buffer_usec,
            (double) i->sink_usec,
@@ -496,11 +682,11 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info
 }
 
 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
 }
 
 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
-    char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+    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];
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get source output information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -510,15 +696,24 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
-
-
-    snprintf(t, sizeof(t), "%u", i->owner_module);
-    snprintf(k, sizeof(k), "%u", i->client);
+    nl = true;
+
+    pa_snprintf(t, sizeof(t), "%u", i->owner_module);
+    pa_snprintf(k, sizeof(k), "%u", i->client);
+
+    if (short_list_format) {
+        printf("%u\t%u\t%s\t%s\t%s\n",
+               i->index,
+               i->source,
+               i->client != PA_INVALID_INDEX ? k : "-",
+               pa_strnull(i->driver),
+               pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
+        return;
+    }
 
     printf(_("Source Output #%u\n"
              "\tDriver: %s\n"
 
     printf(_("Source Output #%u\n"
              "\tDriver: %s\n"
@@ -527,6 +722,11 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu
              "\tSource: %u\n"
              "\tSample Specification: %s\n"
              "\tChannel Map: %s\n"
              "\tSource: %u\n"
              "\tSample Specification: %s\n"
              "\tChannel Map: %s\n"
+             "\tFormat: %s\n"
+             "\tCorked: %s\n"
+             "\tMute: %s\n"
+             "\tVolume: %s\n"
+             "\t        balance %0.2f\n"
              "\tBuffer Latency: %0.0f usec\n"
              "\tSource Latency: %0.0f usec\n"
              "\tResample method: %s\n"
              "\tBuffer Latency: %0.0f usec\n"
              "\tSource Latency: %0.0f usec\n"
              "\tResample method: %s\n"
@@ -538,6 +738,11 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu
            i->source,
            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
            i->source,
            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
+           pa_format_info_snprint(f, sizeof(f), i->format),
+           pa_yes_no(i->corked),
+           pa_yes_no(i->mute),
+           pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
+           pa_cvolume_get_balance(&i->volume, &i->channel_map),
            (double) i->buffer_usec,
            (double) i->source_usec,
            i->resample_method ? i->resample_method : _("n/a"),
            (double) i->buffer_usec,
            (double) i->source_usec,
            i->resample_method ? i->resample_method : _("n/a"),
@@ -547,11 +752,11 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu
 }
 
 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
 }
 
 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
-    char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+    char t[PA_BYTES_SNPRINT_MAX], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
     char *pl;
 
     if (is_last < 0) {
     char *pl;
 
     if (is_last < 0) {
-        fprintf(stderr, _("Failed to get sample information: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -561,20 +766,28 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int
         return;
     }
 
         return;
     }
 
-    assert(i);
+    pa_assert(i);
 
 
-    if (nl)
+    if (nl && !short_list_format)
         printf("\n");
         printf("\n");
-    nl = 1;
+    nl = true;
 
     pa_bytes_snprint(t, sizeof(t), i->bytes);
 
 
     pa_bytes_snprint(t, sizeof(t), i->bytes);
 
+    if (short_list_format) {
+        printf("%u\t%s\t%s\t%0.3f\n",
+               i->index,
+               i->name,
+               pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "-",
+               (double) i->duration/1000000.0);
+        return;
+    }
+
     printf(_("Sample #%u\n"
              "\tName: %s\n"
              "\tSample Specification: %s\n"
              "\tChannel Map: %s\n"
              "\tVolume: %s\n"
     printf(_("Sample #%u\n"
              "\tName: %s\n"
              "\tSample Specification: %s\n"
              "\tChannel Map: %s\n"
              "\tVolume: %s\n"
-             "\t        %s\n"
              "\t        balance %0.2f\n"
              "\tDuration: %0.1fs\n"
              "\tSize: %s\n"
              "\t        balance %0.2f\n"
              "\tDuration: %0.1fs\n"
              "\tSize: %s\n"
@@ -585,8 +798,7 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int
            i->name,
            pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
            pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
            i->name,
            pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
            pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
-           pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
-           pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
+           pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
            (double) i->duration/1000000.0,
            t,
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
            (double) i->duration/1000000.0,
            t,
@@ -599,7 +811,7 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int
 
 static void simple_callback(pa_context *c, int success, void *userdata) {
     if (!success) {
 
 static void simple_callback(pa_context *c, int success, void *userdata) {
     if (!success) {
-        fprintf(stderr, _("Failure: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -609,7 +821,7 @@ static void simple_callback(pa_context *c, int success, void *userdata) {
 
 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
     if (idx == PA_INVALID_INDEX) {
 
 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
     if (idx == PA_INVALID_INDEX) {
-        fprintf(stderr, _("Failure: %s\n"), pa_strerror(pa_context_errno(c)));
+        pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -619,8 +831,222 @@ static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
     complete_action();
 }
 
     complete_action();
 }
 
+static void volume_relative_adjust(pa_cvolume *cv) {
+    pa_assert((volume_flags & VOL_RELATIVE) == VOL_RELATIVE);
+
+    /* Relative volume change is additive in case of UINT or PERCENT
+     * and multiplicative for LINEAR or DECIBEL */
+    if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
+        pa_volume_t v = pa_cvolume_avg(cv);
+        v = v + volume < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + volume - PA_VOLUME_NORM;
+        pa_cvolume_set(cv, 1, v);
+    }
+    if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) {
+        pa_sw_cvolume_multiply_scalar(cv, cv, volume);
+    }
+}
+
+static void unload_module_by_name_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
+    static bool unloaded = false;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last) {
+        if (unloaded == false)
+            pa_log(_("Failed to unload module: Module %s not loaded"), module_name);
+        complete_action();
+        return;
+    }
+
+    pa_assert(i);
+
+    if (pa_streq(module_name, i->name)) {
+        unloaded = true;
+        actions++;
+        pa_operation_unref(pa_context_unload_module(c, i->index, simple_callback, NULL));
+    }
+}
+
+static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
+    pa_cvolume cv;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    cv = i->volume;
+    volume_relative_adjust(&cv);
+    pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
+}
+
+static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
+    pa_cvolume cv;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    cv = i->volume;
+    volume_relative_adjust(&cv);
+    pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
+}
+
+static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
+    pa_cvolume cv;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    cv = i->volume;
+    volume_relative_adjust(&cv);
+    pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
+}
+
+static void get_source_output_volume_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) {
+    pa_cvolume cv;
+
+    if (is_last < 0) {
+        pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(o);
+
+    cv = o->volume;
+    volume_relative_adjust(&cv);
+    pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL));
+}
+
+static void sink_toggle_mute_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
+    if (is_last < 0) {
+        pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    pa_operation_unref(pa_context_set_sink_mute_by_name(c, i->name, !i->mute, simple_callback, NULL));
+}
+
+static void source_toggle_mute_callback(pa_context *c, const pa_source_info *o, int is_last, void *userdata) {
+    if (is_last < 0) {
+        pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(o);
+
+    pa_operation_unref(pa_context_set_source_mute_by_name(c, o->name, !o->mute, simple_callback, NULL));
+}
+
+static void sink_input_toggle_mute_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
+    if (is_last < 0) {
+        pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(i);
+
+    pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, !i->mute, simple_callback, NULL));
+}
+
+static void source_output_toggle_mute_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) {
+    if (is_last < 0) {
+        pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
+        quit(1);
+        return;
+    }
+
+    if (is_last)
+        return;
+
+    pa_assert(o);
+
+    pa_operation_unref(pa_context_set_source_output_mute(c, o->index, !o->mute, simple_callback, NULL));
+}
+
+/* PA_MAX_FORMATS is defined in internal.h so we just define a sane value here */
+#define MAX_FORMATS 256
+
+static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) {
+    pa_format_info *f_arr[MAX_FORMATS];
+    char *format = NULL;
+    const char *state = NULL;
+    int i = 0;
+
+    while ((format = pa_split(str, ";", &state))) {
+        pa_format_info *f = pa_format_info_from_string(pa_strip(format));
+
+        if (!f) {
+            pa_log(_("Failed to set format: invalid format string %s"), format);
+            goto error;
+        }
+
+        f_arr[i++] = f;
+        pa_xfree(format);
+    }
+
+    pa_operation_unref(pa_ext_device_restore_save_formats(c, PA_DEVICE_TYPE_SINK, sink, i, f_arr, simple_callback, NULL));
+
+done:
+    if (format)
+        pa_xfree(format);
+    while(i--)
+        pa_format_info_free(f_arr[i]);
+
+    return;
+
+error:
+    while(i--)
+        pa_format_info_free(f_arr[i]);
+    quit(1);
+    goto done;
+}
+
 static void stream_state_callback(pa_stream *s, void *userdata) {
 static void stream_state_callback(pa_stream *s, void *userdata) {
-    assert(s);
+    pa_assert(s);
 
     switch (pa_stream_get_state(s)) {
         case PA_STREAM_CREATING:
 
     switch (pa_stream_get_state(s)) {
         case PA_STREAM_CREATING:
@@ -633,7 +1059,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) {
 
         case PA_STREAM_FAILED:
         default:
 
         case PA_STREAM_FAILED:
         default:
-            fprintf(stderr, _("Failed to upload sample: %s\n"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
+            pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
             quit(1);
     }
 }
             quit(1);
     }
 }
@@ -641,16 +1067,16 @@ static void stream_state_callback(pa_stream *s, void *userdata) {
 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
     sf_count_t l;
     float *d;
 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
     sf_count_t l;
     float *d;
-    assert(s && length && sndfile);
+    pa_assert(s && length && sndfile);
 
     d = pa_xmalloc(length);
 
 
     d = pa_xmalloc(length);
 
-    assert(sample_length >= length);
+    pa_assert(sample_length >= length);
     l = (sf_count_t) (length/pa_frame_size(&sample_spec));
 
     if ((sf_readf_float(sndfile, d, l)) != l) {
         pa_xfree(d);
     l = (sf_count_t) (length/pa_frame_size(&sample_spec));
 
     if ((sf_readf_float(sndfile, d, l)) != l) {
         pa_xfree(d);
-        fprintf(stderr, _("Premature end of file\n"));
+        pa_log(_("Premature end of file"));
         quit(1);
         return;
     }
         quit(1);
         return;
     }
@@ -659,14 +1085,76 @@ static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
 
     sample_length -= length;
 
 
     sample_length -= length;
 
-    if (sample_length  <= 0) {
+    if (sample_length <= 0) {
         pa_stream_set_write_callback(sample_stream, NULL, NULL);
         pa_stream_finish_upload(sample_stream);
     }
 }
 
         pa_stream_set_write_callback(sample_stream, NULL, NULL);
         pa_stream_finish_upload(sample_stream);
     }
 }
 
+static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) {
+
+    switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
+
+    case PA_SUBSCRIPTION_EVENT_NEW:
+        return _("new");
+
+    case PA_SUBSCRIPTION_EVENT_CHANGE:
+        return _("change");
+
+    case PA_SUBSCRIPTION_EVENT_REMOVE:
+        return _("remove");
+    }
+
+    return _("unknown");
+}
+
+static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) {
+
+    switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
+
+    case PA_SUBSCRIPTION_EVENT_SINK:
+        return _("sink");
+
+    case PA_SUBSCRIPTION_EVENT_SOURCE:
+        return _("source");
+
+    case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
+        return _("sink-input");
+
+    case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
+        return _("source-output");
+
+    case PA_SUBSCRIPTION_EVENT_MODULE:
+        return _("module");
+
+    case PA_SUBSCRIPTION_EVENT_CLIENT:
+        return _("client");
+
+    case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
+        return _("sample-cache");
+
+    case PA_SUBSCRIPTION_EVENT_SERVER:
+        return _("server");
+
+    case PA_SUBSCRIPTION_EVENT_CARD:
+        return _("card");
+    }
+
+    return _("unknown");
+}
+
+static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
+    pa_assert(c);
+
+    printf(_("Event '%s' on %s #%u\n"),
+           subscription_event_type_to_string(t),
+           subscription_event_facility_to_string(t),
+           idx);
+    fflush(stdout);
+}
+
 static void context_state_callback(pa_context *c, void *userdata) {
 static void context_state_callback(pa_context *c, void *userdata) {
-    assert(c);
+    pa_assert(c);
     switch (pa_context_get_state(c)) {
         case PA_CONTEXT_CONNECTING:
         case PA_CONTEXT_AUTHORIZING:
     switch (pa_context_get_state(c)) {
         case PA_CONTEXT_CONNECTING:
         case PA_CONTEXT_AUTHORIZING:
@@ -676,13 +1164,17 @@ static void context_state_callback(pa_context *c, void *userdata) {
         case PA_CONTEXT_READY:
             switch (action) {
                 case STAT:
         case PA_CONTEXT_READY:
             switch (action) {
                 case STAT:
-                    actions = 2;
                     pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
                     pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
+                    if (short_list_format)
+                        break;
+                    actions++;
+
+                case INFO:
                     pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
                     break;
 
                 case PLAY_SAMPLE:
                     pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
                     break;
 
                 case PLAY_SAMPLE:
-                    pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL));
+                    pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL));
                     break;
 
                 case REMOVE_SAMPLE:
                     break;
 
                 case REMOVE_SAMPLE:
@@ -691,7 +1183,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
 
                 case UPLOAD_SAMPLE:
                     sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
 
                 case UPLOAD_SAMPLE:
                     sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
-                    assert(sample_stream);
+                    pa_assert(sample_stream);
 
                     pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
                     pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
 
                     pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
                     pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
@@ -703,15 +1195,36 @@ static void context_state_callback(pa_context *c, void *userdata) {
                     break;
 
                 case LIST:
                     break;
 
                 case LIST:
-                    actions = 8;
-                    pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
-                    pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
+                    if (list_type) {
+                        if (pa_streq(list_type, "modules"))
+                            pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
+                        else if (pa_streq(list_type, "sinks"))
+                            pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
+                        else if (pa_streq(list_type, "sources"))
+                            pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
+                        else if (pa_streq(list_type, "sink-inputs"))
+                            pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
+                        else if (pa_streq(list_type, "source-outputs"))
+                            pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
+                        else if (pa_streq(list_type, "clients"))
+                            pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
+                        else if (pa_streq(list_type, "samples"))
+                            pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
+                        else if (pa_streq(list_type, "cards"))
+                            pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
+                        else
+                            pa_assert_not_reached();
+                    } else {
+                        actions = 8;
+                        pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
+                        pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
+                    }
                     break;
 
                 case MOVE_SINK_INPUT:
                     break;
 
                 case MOVE_SINK_INPUT:
@@ -727,7 +1240,10 @@ static void context_state_callback(pa_context *c, void *userdata) {
                     break;
 
                 case UNLOAD_MODULE:
                     break;
 
                 case UNLOAD_MODULE:
-                    pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
+                    if (module_name)
+                        pa_operation_unref(pa_context_get_module_info_list(c, unload_module_by_name_callback, NULL));
+                    else
+                        pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
                     break;
 
                 case SUSPEND_SINK:
                     break;
 
                 case SUSPEND_SINK:
@@ -748,8 +1264,118 @@ static void context_state_callback(pa_context *c, void *userdata) {
                     pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
                     break;
 
                     pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
                     break;
 
+                case SET_SINK_PORT:
+                    pa_operation_unref(pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL));
+                    break;
+
+                case SET_DEFAULT_SINK:
+                    pa_operation_unref(pa_context_set_default_sink(c, sink_name, simple_callback, NULL));
+                    break;
+
+                case SET_SOURCE_PORT:
+                    pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL));
+                    break;
+
+                case SET_DEFAULT_SOURCE:
+                    pa_operation_unref(pa_context_set_default_source(c, source_name, simple_callback, NULL));
+                    break;
+
+                case SET_SINK_MUTE:
+                    if (mute == TOGGLE_MUTE)
+                        pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, sink_toggle_mute_callback, NULL));
+                    else
+                        pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL));
+                    break;
+
+                case SET_SOURCE_MUTE:
+                    if (mute == TOGGLE_MUTE)
+                        pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, source_toggle_mute_callback, NULL));
+                    else
+                        pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL));
+                    break;
+
+                case SET_SINK_INPUT_MUTE:
+                    if (mute == TOGGLE_MUTE)
+                        pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, sink_input_toggle_mute_callback, NULL));
+                    else
+                        pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
+                    break;
+
+                case SET_SOURCE_OUTPUT_MUTE:
+                    if (mute == TOGGLE_MUTE)
+                        pa_operation_unref(pa_context_get_source_output_info(c, source_output_idx, source_output_toggle_mute_callback, NULL));
+                    else
+                        pa_operation_unref(pa_context_set_source_output_mute(c, source_output_idx, mute, simple_callback, NULL));
+                    break;
+
+                case SET_SINK_VOLUME:
+                    if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+                        pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
+                    } else {
+                        pa_cvolume v;
+                        pa_cvolume_set(&v, 1, volume);
+                        pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
+                    }
+                    break;
+
+                case SET_SOURCE_VOLUME:
+                    if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+                        pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
+                    } else {
+                        pa_cvolume v;
+                        pa_cvolume_set(&v, 1, volume);
+                        pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
+                    }
+                    break;
+
+                case SET_SINK_INPUT_VOLUME:
+                    if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+                        pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
+                    } else {
+                        pa_cvolume v;
+                        pa_cvolume_set(&v, 1, volume);
+                        pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
+                    }
+                    break;
+
+                case SET_SOURCE_OUTPUT_VOLUME:
+                    if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+                        pa_operation_unref(pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL));
+                    } else {
+                        pa_cvolume v;
+                        pa_cvolume_set(&v, 1, volume);
+                        pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &v, simple_callback, NULL));
+                    }
+                    break;
+
+                case SET_SINK_FORMATS:
+                    set_sink_formats(c, sink_idx, formats);
+                    break;
+
+                case SET_PORT_LATENCY_OFFSET:
+                    pa_operation_unref(pa_context_set_port_latency_offset(c, card_name, port_name, latency_offset, simple_callback, NULL));
+                    break;
+
+                case SUBSCRIBE:
+                    pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
+
+                    pa_operation_unref(pa_context_subscribe(
+                                              c,
+                                              PA_SUBSCRIPTION_MASK_SINK|
+                                              PA_SUBSCRIPTION_MASK_SOURCE|
+                                              PA_SUBSCRIPTION_MASK_SINK_INPUT|
+                                              PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
+                                              PA_SUBSCRIPTION_MASK_MODULE|
+                                              PA_SUBSCRIPTION_MASK_CLIENT|
+                                              PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
+                                              PA_SUBSCRIPTION_MASK_SERVER|
+                                              PA_SUBSCRIPTION_MASK_CARD,
+                                              NULL,
+                                              NULL));
+                    break;
+
                 default:
                 default:
-                    assert(0);
+                    pa_assert_not_reached();
             }
             break;
 
             }
             break;
 
@@ -759,45 +1385,131 @@ static void context_state_callback(pa_context *c, void *userdata) {
 
         case PA_CONTEXT_FAILED:
         default:
 
         case PA_CONTEXT_FAILED:
         default:
-            fprintf(stderr, _("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
+            pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
             quit(1);
     }
 }
 
 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
             quit(1);
     }
 }
 
 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
-    fprintf(stderr, _("Got SIGINT, exiting.\n"));
+    pa_log(_("Got SIGINT, exiting."));
     quit(0);
 }
 
     quit(0);
 }
 
+static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) {
+    double v;
+    char *vs;
+
+    pa_assert(vol_spec);
+    pa_assert(vol);
+    pa_assert(vol_flags);
+
+    vs = pa_xstrdup(vol_spec);
+
+    *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;
+    if (strchr(vs, '.'))
+        *vol_flags |= VOL_LINEAR;
+    if (pa_endswith(vs, "%")) {
+        *vol_flags |= VOL_PERCENT;
+        vs[strlen(vs)-1] = 0;
+    }
+    if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) {
+        *vol_flags |= VOL_DECIBEL;
+        vs[strlen(vs)-2] = 0;
+    }
+
+    if (pa_atod(vs, &v) < 0) {
+        pa_log(_("Invalid volume specification"));
+        pa_xfree(vs);
+        return -1;
+    }
+
+    pa_xfree(vs);
+
+    if ((*vol_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+        if ((*vol_flags & 0x0F) == VOL_UINT)
+            v += (double) PA_VOLUME_NORM;
+        if ((*vol_flags & 0x0F) == VOL_PERCENT)
+            v += 100.0;
+        if ((*vol_flags & 0x0F) == VOL_LINEAR)
+            v += 1.0;
+    }
+    if ((*vol_flags & 0x0F) == VOL_PERCENT)
+        v = v * (double) PA_VOLUME_NORM / 100;
+    if ((*vol_flags & 0x0F) == VOL_LINEAR)
+        v = pa_sw_volume_from_linear(v);
+    if ((*vol_flags & 0x0F) == VOL_DECIBEL)
+        v = pa_sw_volume_from_dB(v);
+
+    if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) {
+        pa_log(_("Volume outside permissible range.\n"));
+        return -1;
+    }
+
+    *vol = (pa_volume_t) v;
+
+    return 0;
+}
+
+static enum mute_flags parse_mute(const char *mute_text) {
+    int b;
+
+    pa_assert(mute_text);
+
+    if (pa_streq("toggle", mute_text))
+        return TOGGLE_MUTE;
+
+    b = pa_parse_boolean(mute_text);
+    switch (b) {
+        case 0:
+            return UNMUTE;
+        case 1:
+            return MUTE;
+        default:
+            return INVALID_MUTE;
+    }
+}
+
 static void help(const char *argv0) {
 
 static void help(const char *argv0) {
 
-    printf(_("%s [options] stat\n"
-             "%s [options] list\n"
-             "%s [options] exit\n"
-             "%s [options] upload-sample FILENAME [NAME]\n"
-             "%s [options] play-sample NAME [SINK]\n"
-             "%s [options] remove-sample NAME\n"
-             "%s [options] move-sink-input ID SINK\n"
-             "%s [options] move-source-output ID SOURCE\n"
-             "%s [options] load-module NAME [ARGS ...]\n"
-             "%s [options] unload-module ID\n"
-             "%s [options] suspend-sink [SINK] 1|0\n"
-             "%s [options] suspend-source [SOURCE] 1|0\n"
-             "%s [options] set-card-profile [CARD] [PROFILE] \n\n"
+    printf("%s %s %s\n",    argv0, _("[options]"), "stat [short]");
+    printf("%s %s %s\n",    argv0, _("[options]"), "info");
+    printf("%s %s %s %s\n", argv0, _("[options]"), "list [short]", _("[TYPE]"));
+    printf("%s %s %s\n",    argv0, _("[options]"), "exit");
+    printf("%s %s %s %s\n", argv0, _("[options]"), "upload-sample", _("FILENAME [NAME]"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "play-sample ", _("NAME [SINK]"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "remove-sample ", _("NAME"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "load-module ", _("NAME [ARGS ...]"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "unload-module ", _("NAME|#N"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "move-(sink-input|source-output)", _("#N SINK|SOURCE"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "suspend-(sink|source)", _("NAME|#N 1|0"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-card-profile ", _("CARD PROFILE"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-default-(sink|source)", _("NAME"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-port", _("NAME|#N PORT"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-volume", _("NAME|#N VOLUME"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-volume", _("#N VOLUME"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-mute", _("NAME|#N 1|0|toggle"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-mute", _("#N 1|0|toggle"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats", _("#N FORMATS"));
+    printf("%s %s %s %s\n", argv0, _("[options]"), "set-port-latency-offset", _("CARD-NAME|CARD-#N PORT OFFSET"));
+    printf("%s %s %s\n",    argv0, _("[options]"), "subscribe");
+    printf(_("\nThe special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and @DEFAULT_MONITOR@\n"
+             "can be used to specify the default sink, source and monitor.\n"));
+
+    printf(_("\n"
              "  -h, --help                            Show this help\n"
              "      --version                         Show version\n\n"
              "  -s, --server=SERVER                   The name of the server to connect to\n"
              "  -h, --help                            Show this help\n"
              "      --version                         Show version\n\n"
              "  -s, --server=SERVER                   The name of the server to connect to\n"
-             "  -n, --client-name=NAME                How to call this client on the server\n"),
-           argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0);
+             "  -n, --client-name=NAME                How to call this client on the server\n"));
 }
 
 }
 
-enum { ARG_VERSION = 256 };
+enum {
+    ARG_VERSION = 256
+};
 
 int main(int argc, char *argv[]) {
 
 int main(int argc, char *argv[]) {
-    pa_mainloop* m = NULL;
-    char tmp[PATH_MAX];
-    int ret = 1, r, c;
-    char *server = NULL, *client_name = NULL, *bn;
+    pa_mainloop *m = NULL;
+    int ret = 1, c;
+    char *server = NULL, *bn;
 
     static const struct option long_options[] = {
         {"server",      1, NULL, 's'},
 
     static const struct option long_options[] = {
         {"server",      1, NULL, 's'},
@@ -808,12 +1520,13 @@ int main(int argc, char *argv[]) {
     };
 
     setlocale(LC_ALL, "");
     };
 
     setlocale(LC_ALL, "");
+#ifdef ENABLE_NLS
     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
+#endif
 
 
-    if (!(bn = strrchr(argv[0], '/')))
-        bn = argv[0];
-    else
-        bn++;
+    bn = pa_path_get_filename(argv[0]);
+
+    proplist = pa_proplist_new();
 
     while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
         switch (c) {
 
     while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
         switch (c) {
@@ -837,101 +1550,135 @@ int main(int argc, char *argv[]) {
                 server = pa_xstrdup(optarg);
                 break;
 
                 server = pa_xstrdup(optarg);
                 break;
 
-            case 'n':
-                pa_xfree(client_name);
-                client_name = pa_xstrdup(optarg);
+            case 'n': {
+                char *t;
+
+                if (!(t = pa_locale_to_utf8(optarg)) ||
+                    pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
+
+                    pa_log(_("Invalid client name '%s'"), t ? t : optarg);
+                    pa_xfree(t);
+                    goto quit;
+                }
+
+                pa_xfree(t);
                 break;
                 break;
+            }
 
             default:
                 goto quit;
         }
     }
 
 
             default:
                 goto quit;
         }
     }
 
-    if (!client_name)
-        client_name = pa_xstrdup(bn);
-
     if (optind < argc) {
     if (optind < argc) {
-        if (!strcmp(argv[optind], "stat"))
+        if (pa_streq(argv[optind], "stat")) {
             action = STAT;
             action = STAT;
-        else if (!strcmp(argv[optind], "exit"))
+            short_list_format = false;
+            if (optind+1 < argc && pa_streq(argv[optind+1], "short"))
+                short_list_format = true;
+
+        } else if (pa_streq(argv[optind], "info"))
+            action = INFO;
+
+        else if (pa_streq(argv[optind], "exit"))
             action = EXIT;
             action = EXIT;
-        else if (!strcmp(argv[optind], "list"))
+
+        else if (pa_streq(argv[optind], "list")) {
             action = LIST;
             action = LIST;
-        else if (!strcmp(argv[optind], "upload-sample")) {
-            struct SF_INFO sfinfo;
+
+            for (int i = optind+1; i < argc; i++) {
+                if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
+                    pa_streq(argv[i], "sinks")   || pa_streq(argv[i], "sink-inputs") ||
+                    pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
+                    pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
+                    list_type = pa_xstrdup(argv[i]);
+                } else if (pa_streq(argv[i], "short")) {
+                    short_list_format = true;
+                } else {
+                    pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
+                    goto quit;
+                }
+            }
+
+        } else if (pa_streq(argv[optind], "upload-sample")) {
+            struct SF_INFO sfi;
             action = UPLOAD_SAMPLE;
 
             if (optind+1 >= argc) {
             action = UPLOAD_SAMPLE;
 
             if (optind+1 >= argc) {
-                fprintf(stderr, _("Please specify a sample file to load\n"));
+                pa_log(_("Please specify a sample file to load"));
                 goto quit;
             }
 
             if (optind+2 < argc)
                 sample_name = pa_xstrdup(argv[optind+2]);
             else {
                 goto quit;
             }
 
             if (optind+2 < argc)
                 sample_name = pa_xstrdup(argv[optind+2]);
             else {
-                char *f = strrchr(argv[optind+1], '/');
-                size_t n;
-                if (f)
-                    f++;
-                else
-                    f = argv[optind];
-
-                n = strcspn(f, ".");
-                strncpy(tmp, f, n);
-                tmp[n] = 0;
-                sample_name = pa_xstrdup(tmp);
+                char *f = pa_path_get_filename(argv[optind+1]);
+                sample_name = pa_xstrndup(f, strcspn(f, "."));
             }
 
             }
 
-            memset(&sfinfo, 0, sizeof(sfinfo));
-            if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) {
-                fprintf(stderr, _("Failed to open sound file.\n"));
+            pa_zero(sfi);
+            if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
+                pa_log(_("Failed to open sound file."));
                 goto quit;
             }
 
                 goto quit;
             }
 
+            if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
+                pa_log(_("Failed to determine sample specification from file."));
+                goto quit;
+            }
             sample_spec.format = PA_SAMPLE_FLOAT32;
             sample_spec.format = PA_SAMPLE_FLOAT32;
-            sample_spec.rate = (uint32_t) sfinfo.samplerate;
-            sample_spec.channels = (uint8_t) sfinfo.channels;
 
 
-            sample_length = (size_t)sfinfo.frames*pa_frame_size(&sample_spec);
-        } else if (!strcmp(argv[optind], "play-sample")) {
+            if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
+                if (sample_spec.channels > 2)
+                    pa_log(_("Warning: Failed to determine sample specification from file."));
+                pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
+            }
+
+            pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
+            sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
+
+        } else if (pa_streq(argv[optind], "play-sample")) {
             action = PLAY_SAMPLE;
             if (argc != optind+2 && argc != optind+3) {
             action = PLAY_SAMPLE;
             if (argc != optind+2 && argc != optind+3) {
-                fprintf(stderr, _("You have to specify a sample name to play\n"));
+                pa_log(_("You have to specify a sample name to play"));
                 goto quit;
             }
 
             sample_name = pa_xstrdup(argv[optind+1]);
 
             if (optind+2 < argc)
                 goto quit;
             }
 
             sample_name = pa_xstrdup(argv[optind+1]);
 
             if (optind+2 < argc)
-                device = pa_xstrdup(argv[optind+2]);
+                sink_name = pa_xstrdup(argv[optind+2]);
 
 
-        } else if (!strcmp(argv[optind], "remove-sample")) {
+        } else if (pa_streq(argv[optind], "remove-sample")) {
             action = REMOVE_SAMPLE;
             if (argc != optind+2) {
             action = REMOVE_SAMPLE;
             if (argc != optind+2) {
-                fprintf(stderr, _("You have to specify a sample name to remove\n"));
+                pa_log(_("You have to specify a sample name to remove"));
                 goto quit;
             }
 
             sample_name = pa_xstrdup(argv[optind+1]);
                 goto quit;
             }
 
             sample_name = pa_xstrdup(argv[optind+1]);
-        } else if (!strcmp(argv[optind], "move-sink-input")) {
+
+        } else if (pa_streq(argv[optind], "move-sink-input")) {
             action = MOVE_SINK_INPUT;
             if (argc != optind+3) {
             action = MOVE_SINK_INPUT;
             if (argc != optind+3) {
-                fprintf(stderr, _("You have to specify a sink input index and a sink\n"));
+                pa_log(_("You have to specify a sink input index and a sink"));
                 goto quit;
             }
 
             sink_input_idx = (uint32_t) atoi(argv[optind+1]);
             sink_name = pa_xstrdup(argv[optind+2]);
                 goto quit;
             }
 
             sink_input_idx = (uint32_t) atoi(argv[optind+1]);
             sink_name = pa_xstrdup(argv[optind+2]);
-        } else if (!strcmp(argv[optind], "move-source-output")) {
+
+        } else if (pa_streq(argv[optind], "move-source-output")) {
             action = MOVE_SOURCE_OUTPUT;
             if (argc != optind+3) {
             action = MOVE_SOURCE_OUTPUT;
             if (argc != optind+3) {
-                fprintf(stderr, _("You have to specify a source output index and a source\n"));
+                pa_log(_("You have to specify a source output index and a source"));
                 goto quit;
             }
 
             source_output_idx = (uint32_t) atoi(argv[optind+1]);
             source_name = pa_xstrdup(argv[optind+2]);
                 goto quit;
             }
 
             source_output_idx = (uint32_t) atoi(argv[optind+1]);
             source_name = pa_xstrdup(argv[optind+2]);
-        } else if (!strcmp(argv[optind], "load-module")) {
+
+        } else if (pa_streq(argv[optind], "load-module")) {
             int i;
             size_t n = 0;
             char *p;
             int i;
             size_t n = 0;
             char *p;
@@ -939,7 +1686,7 @@ int main(int argc, char *argv[]) {
             action = LOAD_MODULE;
 
             if (argc <= optind+1) {
             action = LOAD_MODULE;
 
             if (argc <= optind+1) {
-                fprintf(stderr, _("You have to specify a module name and arguments.\n"));
+                pa_log(_("You have to specify a module name and arguments."));
                 goto quit;
             }
 
                 goto quit;
             }
 
@@ -955,53 +1702,265 @@ int main(int argc, char *argv[]) {
                     p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
             }
 
                     p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
             }
 
-        } else if (!strcmp(argv[optind], "unload-module")) {
+        } else if (pa_streq(argv[optind], "unload-module")) {
             action = UNLOAD_MODULE;
 
             if (argc != optind+2) {
             action = UNLOAD_MODULE;
 
             if (argc != optind+2) {
-                fprintf(stderr, _("You have to specify a module index\n"));
+                pa_log(_("You have to specify a module index or name"));
                 goto quit;
             }
 
                 goto quit;
             }
 
-            module_index = (uint32_t) atoi(argv[optind+1]);
+            if (pa_atou(argv[optind + 1], &module_index) < 0)
+                module_name = argv[optind + 1];
+
+        } else if (pa_streq(argv[optind], "suspend-sink")) {
+            int b;
 
 
-        } else if (!strcmp(argv[optind], "suspend-sink")) {
             action = SUSPEND_SINK;
 
             if (argc > optind+3 || optind+1 >= argc) {
             action = SUSPEND_SINK;
 
             if (argc > optind+3 || optind+1 >= argc) {
-                fprintf(stderr, _("You may not specify more than one sink. You have to specify a boolean value.\n"));
+                pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
                 goto quit;
             }
 
                 goto quit;
             }
 
-            suspend = pa_parse_boolean(argv[argc-1]);
+            if ((b = pa_parse_boolean(argv[argc-1])) < 0) {
+                pa_log(_("Invalid suspend specification."));
+                goto quit;
+            }
+
+            suspend = !!b;
 
             if (argc > optind+2)
                 sink_name = pa_xstrdup(argv[optind+1]);
 
 
             if (argc > optind+2)
                 sink_name = pa_xstrdup(argv[optind+1]);
 
-        } else if (!strcmp(argv[optind], "suspend-source")) {
+        } else if (pa_streq(argv[optind], "suspend-source")) {
+            int b;
+
             action = SUSPEND_SOURCE;
 
             if (argc > optind+3 || optind+1 >= argc) {
             action = SUSPEND_SOURCE;
 
             if (argc > optind+3 || optind+1 >= argc) {
-                fprintf(stderr, _("You may not specify more than one source. You have to specify a boolean value.\n"));
+                pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
+                goto quit;
+            }
+
+            if ((b = pa_parse_boolean(argv[argc-1])) < 0) {
+                pa_log(_("Invalid suspend specification."));
                 goto quit;
             }
 
                 goto quit;
             }
 
-            suspend = pa_parse_boolean(argv[argc-1]);
+            suspend = !!b;
 
             if (argc > optind+2)
                 source_name = pa_xstrdup(argv[optind+1]);
 
             if (argc > optind+2)
                 source_name = pa_xstrdup(argv[optind+1]);
-        } else if (!strcmp(argv[optind], "set-card-profile")) {
+        } else if (pa_streq(argv[optind], "set-card-profile")) {
             action = SET_CARD_PROFILE;
 
             if (argc != optind+3) {
             action = SET_CARD_PROFILE;
 
             if (argc != optind+3) {
-                fprintf(stderr, _("You have to specify a card name/index and a profile name\n"));
+                pa_log(_("You have to specify a card name/index and a profile name"));
                 goto quit;
             }
 
             card_name = pa_xstrdup(argv[optind+1]);
             profile_name = pa_xstrdup(argv[optind+2]);
 
                 goto quit;
             }
 
             card_name = pa_xstrdup(argv[optind+1]);
             profile_name = pa_xstrdup(argv[optind+2]);
 
-        } else if (!strcmp(argv[optind], "help")) {
+        } else if (pa_streq(argv[optind], "set-sink-port")) {
+            action = SET_SINK_PORT;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a sink name/index and a port name"));
+                goto quit;
+            }
+
+            sink_name = pa_xstrdup(argv[optind+1]);
+            port_name = pa_xstrdup(argv[optind+2]);
+
+        } else if (pa_streq(argv[optind], "set-default-sink")) {
+            action = SET_DEFAULT_SINK;
+
+            if (argc != optind+2) {
+                pa_log(_("You have to specify a sink name"));
+                goto quit;
+            }
+
+            sink_name = pa_xstrdup(argv[optind+1]);
+
+        } else if (pa_streq(argv[optind], "set-source-port")) {
+            action = SET_SOURCE_PORT;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a source name/index and a port name"));
+                goto quit;
+            }
+
+            source_name = pa_xstrdup(argv[optind+1]);
+            port_name = pa_xstrdup(argv[optind+2]);
+
+        } else if (pa_streq(argv[optind], "set-default-source")) {
+            action = SET_DEFAULT_SOURCE;
+
+            if (argc != optind+2) {
+                pa_log(_("You have to specify a source name"));
+                goto quit;
+            }
+
+            source_name = pa_xstrdup(argv[optind+1]);
+
+        } else if (pa_streq(argv[optind], "set-sink-volume")) {
+            action = SET_SINK_VOLUME;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a sink name/index and a volume"));
+                goto quit;
+            }
+
+            sink_name = pa_xstrdup(argv[optind+1]);
+
+            if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
+                goto quit;
+
+        } else if (pa_streq(argv[optind], "set-source-volume")) {
+            action = SET_SOURCE_VOLUME;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a source name/index and a volume"));
+                goto quit;
+            }
+
+            source_name = pa_xstrdup(argv[optind+1]);
+
+            if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
+                goto quit;
+
+        } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
+            action = SET_SINK_INPUT_VOLUME;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a sink input index and a volume"));
+                goto quit;
+            }
+
+            if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
+                pa_log(_("Invalid sink input index"));
+                goto quit;
+            }
+
+            if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
+                goto quit;
+
+        } else if (pa_streq(argv[optind], "set-source-output-volume")) {
+            action = SET_SOURCE_OUTPUT_VOLUME;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a source output index and a volume"));
+                goto quit;
+            }
+
+            if (pa_atou(argv[optind+1], &source_output_idx) < 0) {
+                pa_log(_("Invalid source output index"));
+                goto quit;
+            }
+
+            if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
+                goto quit;
+
+        } else if (pa_streq(argv[optind], "set-sink-mute")) {
+            action = SET_SINK_MUTE;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a sink name/index and a mute boolean"));
+                goto quit;
+            }
+
+            if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
+                pa_log(_("Invalid mute specification"));
+                goto quit;
+            }
+
+            sink_name = pa_xstrdup(argv[optind+1]);
+
+        } else if (pa_streq(argv[optind], "set-source-mute")) {
+            action = SET_SOURCE_MUTE;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a source name/index and a mute boolean"));
+                goto quit;
+            }
+
+            if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
+                pa_log(_("Invalid mute specification"));
+                goto quit;
+            }
+
+            source_name = pa_xstrdup(argv[optind+1]);
+
+        } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
+            action = SET_SINK_INPUT_MUTE;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a sink input index and a mute boolean"));
+                goto quit;
+            }
+
+            if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
+                pa_log(_("Invalid sink input index specification"));
+                goto quit;
+            }
+
+            if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
+                pa_log(_("Invalid mute specification"));
+                goto quit;
+            }
+
+        } else if (pa_streq(argv[optind], "set-source-output-mute")) {
+            action = SET_SOURCE_OUTPUT_MUTE;
+
+            if (argc != optind+3) {
+                pa_log(_("You have to specify a source output index and a mute boolean"));
+                goto quit;
+            }
+
+            if (pa_atou(argv[optind+1], &source_output_idx) < 0) {
+                pa_log(_("Invalid source output index specification"));
+                goto quit;
+            }
+
+            if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
+                pa_log(_("Invalid mute specification"));
+                goto quit;
+            }
+
+        } else if (pa_streq(argv[optind], "subscribe"))
+
+            action = SUBSCRIBE;
+
+        else if (pa_streq(argv[optind], "set-sink-formats")) {
+            int32_t tmp;
+
+            if (argc != optind+3 || pa_atoi(argv[optind+1], &tmp) < 0) {
+                pa_log(_("You have to specify a sink index and a semicolon-separated list of supported formats"));
+                goto quit;
+            }
+
+            sink_idx = tmp;
+            action = SET_SINK_FORMATS;
+            formats = pa_xstrdup(argv[optind+2]);
+
+        } else if (pa_streq(argv[optind], "set-port-latency-offset")) {
+            action = SET_PORT_LATENCY_OFFSET;
+
+            if (argc != optind+4) {
+                pa_log(_("You have to specify a card name/index, a port name and a latency offset"));
+                goto quit;
+            }
+
+            card_name = pa_xstrdup(argv[optind+1]);
+            port_name = pa_xstrdup(argv[optind+2]);
+            if (pa_atoi(argv[optind + 3], &latency_offset) < 0) {
+                pa_log(_("Could not parse latency offset"));
+                goto quit;
+            }
+
+        } else if (pa_streq(argv[optind], "help")) {
             help(bn);
             ret = 0;
             goto quit;
             help(bn);
             ret = 0;
             goto quit;
@@ -1009,37 +1968,35 @@ int main(int argc, char *argv[]) {
     }
 
     if (action == NONE) {
     }
 
     if (action == NONE) {
-        fprintf(stderr, _("No valid command specified.\n"));
+        pa_log(_("No valid command specified."));
         goto quit;
     }
 
     if (!(m = pa_mainloop_new())) {
         goto quit;
     }
 
     if (!(m = pa_mainloop_new())) {
-        fprintf(stderr, _("pa_mainloop_new() failed.\n"));
+        pa_log(_("pa_mainloop_new() failed."));
         goto quit;
     }
 
     mainloop_api = pa_mainloop_get_api(m);
 
         goto quit;
     }
 
     mainloop_api = pa_mainloop_get_api(m);
 
-    r = pa_signal_init(mainloop_api);
-    assert(r == 0);
+    pa_assert_se(pa_signal_init(mainloop_api) == 0);
     pa_signal_new(SIGINT, exit_signal_callback, NULL);
     pa_signal_new(SIGINT, exit_signal_callback, NULL);
-#ifdef SIGPIPE
-    signal(SIGPIPE, SIG_IGN);
-#endif
+    pa_signal_new(SIGTERM, exit_signal_callback, NULL);
+    pa_disable_sigpipe();
 
 
-    if (!(context = pa_context_new(mainloop_api, client_name))) {
-        fprintf(stderr, _("pa_context_new() failed.\n"));
+    if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
+        pa_log(_("pa_context_new() failed."));
         goto quit;
     }
 
     pa_context_set_state_callback(context, context_state_callback, NULL);
     if (pa_context_connect(context, server, 0, NULL) < 0) {
         goto quit;
     }
 
     pa_context_set_state_callback(context, context_state_callback, NULL);
     if (pa_context_connect(context, server, 0, NULL) < 0) {
-        fprintf(stderr, _("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
+        pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
         goto quit;
     }
 
     if (pa_mainloop_run(m, &ret) < 0) {
         goto quit;
     }
 
     if (pa_mainloop_run(m, &ret) < 0) {
-        fprintf(stderr, _("pa_mainloop_run() failed.\n"));
+        pa_log(_("pa_mainloop_run() failed."));
         goto quit;
     }
 
         goto quit;
     }
 
@@ -1055,18 +2012,22 @@ quit:
         pa_mainloop_free(m);
     }
 
         pa_mainloop_free(m);
     }
 
-    if (sndfile)
-        sf_close(sndfile);
-
     pa_xfree(server);
     pa_xfree(server);
-    pa_xfree(device);
+    pa_xfree(list_type);
     pa_xfree(sample_name);
     pa_xfree(sink_name);
     pa_xfree(source_name);
     pa_xfree(module_args);
     pa_xfree(sample_name);
     pa_xfree(sink_name);
     pa_xfree(source_name);
     pa_xfree(module_args);
-    pa_xfree(client_name);
     pa_xfree(card_name);
     pa_xfree(profile_name);
     pa_xfree(card_name);
     pa_xfree(profile_name);
+    pa_xfree(port_name);
+    pa_xfree(formats);
+
+    if (sndfile)
+        sf_close(sndfile);
+
+    if (proplist)
+        pa_proplist_free(proplist);
 
     return ret;
 }
 
     return ret;
 }