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