pactl: Add short output format for list action
[pulseaudio-mirror.git] / src / utils / pactl.c
blob194183d48004205f5e987573a2e442855de301b7
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
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.
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.
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 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
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 <limits.h>
34 #include <getopt.h>
35 #include <locale.h>
37 #include <sndfile.h>
39 #include <pulse/i18n.h>
40 #include <pulse/pulseaudio.h>
42 #include <pulsecore/macro.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/sndfile-util.h>
47 static pa_context *context = NULL;
48 static pa_mainloop_api *mainloop_api = NULL;
50 static char
51 *list_type = NULL,
52 *sample_name = NULL,
53 *sink_name = NULL,
54 *source_name = NULL,
55 *module_name = NULL,
56 *module_args = NULL,
57 *card_name = NULL,
58 *profile_name = NULL,
59 *port_name = NULL;
61 static uint32_t
62 sink_input_idx = PA_INVALID_INDEX,
63 source_output_idx = PA_INVALID_INDEX;
65 static pa_bool_t short_list_format = FALSE;
66 static uint32_t module_index;
67 static pa_bool_t suspend;
68 static pa_bool_t mute;
69 static pa_volume_t volume;
70 static enum volume_flags {
71 VOL_UINT = 0,
72 VOL_PERCENT = 1,
73 VOL_LINEAR = 2,
74 VOL_DECIBEL = 3,
75 VOL_ABSOLUTE = 0 << 4,
76 VOL_RELATIVE = 1 << 4,
77 } volume_flags;
79 static pa_proplist *proplist = NULL;
81 static SNDFILE *sndfile = NULL;
82 static pa_stream *sample_stream = NULL;
83 static pa_sample_spec sample_spec;
84 static pa_channel_map channel_map;
85 static size_t sample_length = 0;
86 static int actions = 1;
88 static pa_bool_t nl = FALSE;
90 static enum {
91 NONE,
92 EXIT,
93 STAT,
94 INFO,
95 UPLOAD_SAMPLE,
96 PLAY_SAMPLE,
97 REMOVE_SAMPLE,
98 LIST,
99 MOVE_SINK_INPUT,
100 MOVE_SOURCE_OUTPUT,
101 LOAD_MODULE,
102 UNLOAD_MODULE,
103 SUSPEND_SINK,
104 SUSPEND_SOURCE,
105 SET_CARD_PROFILE,
106 SET_SINK_PORT,
107 SET_SOURCE_PORT,
108 SET_SINK_VOLUME,
109 SET_SOURCE_VOLUME,
110 SET_SINK_INPUT_VOLUME,
111 SET_SINK_MUTE,
112 SET_SOURCE_MUTE,
113 SET_SINK_INPUT_MUTE,
114 SUBSCRIBE
115 } action = NONE;
117 static void quit(int ret) {
118 pa_assert(mainloop_api);
119 mainloop_api->quit(mainloop_api, ret);
122 static void context_drain_complete(pa_context *c, void *userdata) {
123 pa_context_disconnect(c);
126 static void drain(void) {
127 pa_operation *o;
129 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
130 pa_context_disconnect(context);
131 else
132 pa_operation_unref(o);
135 static void complete_action(void) {
136 pa_assert(actions > 0);
138 if (!(--actions))
139 drain();
142 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
143 char s[PA_BYTES_SNPRINT_MAX];
144 if (!i) {
145 pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c)));
146 quit(1);
147 return;
150 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
151 printf(_("Currently in use: %u blocks containing %s bytes total.\n"), i->memblock_total, s);
153 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
154 printf(_("Allocated during whole lifetime: %u blocks containing %s bytes total.\n"), i->memblock_allocated, s);
156 pa_bytes_snprint(s, sizeof(s), i->scache_size);
157 printf(_("Sample cache size: %s\n"), s);
159 complete_action();
162 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
163 char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
165 if (!i) {
166 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
167 quit(1);
168 return;
171 printf(_("Server String: %s\n"
172 "Library Protocol Version: %u\n"
173 "Server Protocol Version: %u\n"
174 "Is Local: %s\n"
175 "Client Index: %u\n"
176 "Tile Size: %zu\n"),
177 pa_context_get_server(c),
178 pa_context_get_protocol_version(c),
179 pa_context_get_server_protocol_version(c),
180 pa_yes_no(pa_context_is_local(c)),
181 pa_context_get_index(c),
182 pa_context_get_tile_size(c, NULL));
184 pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
185 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
187 printf(_("User Name: %s\n"
188 "Host Name: %s\n"
189 "Server Name: %s\n"
190 "Server Version: %s\n"
191 "Default Sample Specification: %s\n"
192 "Default Channel Map: %s\n"
193 "Default Sink: %s\n"
194 "Default Source: %s\n"
195 "Cookie: %04x:%04x\n"),
196 i->user_name,
197 i->host_name,
198 i->server_name,
199 i->server_version,
202 i->default_sink_name,
203 i->default_source_name,
204 i->cookie >> 16,
205 i->cookie & 0xFFFFU);
207 complete_action();
210 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
212 static const char *state_table[] = {
213 [1+PA_SINK_INVALID_STATE] = "n/a",
214 [1+PA_SINK_RUNNING] = "RUNNING",
215 [1+PA_SINK_IDLE] = "IDLE",
216 [1+PA_SINK_SUSPENDED] = "SUSPENDED"
219 char
220 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
221 cv[PA_CVOLUME_SNPRINT_MAX],
222 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
223 v[PA_VOLUME_SNPRINT_MAX],
224 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
225 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
226 char *pl;
228 if (is_last < 0) {
229 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
230 quit(1);
231 return;
234 if (is_last) {
235 complete_action();
236 return;
239 pa_assert(i);
241 if (nl && !short_list_format)
242 printf("\n");
243 nl = TRUE;
245 if (short_list_format) {
246 printf("%u\t%s\t%s\t%s\t%s\n",
247 i->index,
248 i->name,
249 pa_strnull(i->driver),
250 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
251 state_table[1+i->state]);
252 return;
255 printf(_("Sink #%u\n"
256 "\tState: %s\n"
257 "\tName: %s\n"
258 "\tDescription: %s\n"
259 "\tDriver: %s\n"
260 "\tSample Specification: %s\n"
261 "\tChannel Map: %s\n"
262 "\tOwner Module: %u\n"
263 "\tMute: %s\n"
264 "\tVolume: %s%s%s\n"
265 "\t balance %0.2f\n"
266 "\tBase Volume: %s%s%s\n"
267 "\tMonitor Source: %s\n"
268 "\tLatency: %0.0f usec, configured %0.0f usec\n"
269 "\tFlags: %s%s%s%s%s%s\n"
270 "\tProperties:\n\t\t%s\n"),
271 i->index,
272 state_table[1+i->state],
273 i->name,
274 pa_strnull(i->description),
275 pa_strnull(i->driver),
276 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
277 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
278 i->owner_module,
279 pa_yes_no(i->mute),
280 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
281 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
282 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
283 pa_cvolume_get_balance(&i->volume, &i->channel_map),
284 pa_volume_snprint(v, sizeof(v), i->base_volume),
285 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
286 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
287 pa_strnull(i->monitor_source_name),
288 (double) i->latency, (double) i->configured_latency,
289 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
290 i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
291 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
292 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
293 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
294 i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
295 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
297 pa_xfree(pl);
299 if (i->ports) {
300 pa_sink_port_info **p;
302 printf(_("\tPorts:\n"));
303 for (p = i->ports; *p; p++)
304 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
307 if (i->active_port)
308 printf(_("\tActive Port: %s\n"),
309 i->active_port->name);
312 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
314 static const char *state_table[] = {
315 [1+PA_SOURCE_INVALID_STATE] = "n/a",
316 [1+PA_SOURCE_RUNNING] = "RUNNING",
317 [1+PA_SOURCE_IDLE] = "IDLE",
318 [1+PA_SOURCE_SUSPENDED] = "SUSPENDED"
321 char
322 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
323 cv[PA_CVOLUME_SNPRINT_MAX],
324 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
325 v[PA_VOLUME_SNPRINT_MAX],
326 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
327 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
328 char *pl;
330 if (is_last < 0) {
331 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
332 quit(1);
333 return;
336 if (is_last) {
337 complete_action();
338 return;
341 pa_assert(i);
343 if (nl && !short_list_format)
344 printf("\n");
345 nl = TRUE;
347 if (short_list_format) {
348 printf("%u\t%s\t%s\t%s\t%s\n",
349 i->index,
350 i->name,
351 pa_strnull(i->driver),
352 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
353 state_table[1+i->state]);
354 return;
357 printf(_("Source #%u\n"
358 "\tState: %s\n"
359 "\tName: %s\n"
360 "\tDescription: %s\n"
361 "\tDriver: %s\n"
362 "\tSample Specification: %s\n"
363 "\tChannel Map: %s\n"
364 "\tOwner Module: %u\n"
365 "\tMute: %s\n"
366 "\tVolume: %s%s%s\n"
367 "\t balance %0.2f\n"
368 "\tBase Volume: %s%s%s\n"
369 "\tMonitor of Sink: %s\n"
370 "\tLatency: %0.0f usec, configured %0.0f usec\n"
371 "\tFlags: %s%s%s%s%s%s\n"
372 "\tProperties:\n\t\t%s\n"),
373 i->index,
374 state_table[1+i->state],
375 i->name,
376 pa_strnull(i->description),
377 pa_strnull(i->driver),
378 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
379 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
380 i->owner_module,
381 pa_yes_no(i->mute),
382 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
383 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
384 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
385 pa_cvolume_get_balance(&i->volume, &i->channel_map),
386 pa_volume_snprint(v, sizeof(v), i->base_volume),
387 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
388 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
389 i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
390 (double) i->latency, (double) i->configured_latency,
391 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
392 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
393 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
394 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
395 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
396 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
397 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
399 pa_xfree(pl);
401 if (i->ports) {
402 pa_source_port_info **p;
404 printf(_("\tPorts:\n"));
405 for (p = i->ports; *p; p++)
406 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
409 if (i->active_port)
410 printf(_("\tActive Port: %s\n"),
411 i->active_port->name);
414 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
415 char t[32];
416 char *pl;
418 if (is_last < 0) {
419 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
420 quit(1);
421 return;
424 if (is_last) {
425 complete_action();
426 return;
429 pa_assert(i);
431 if (nl && !short_list_format)
432 printf("\n");
433 nl = TRUE;
435 pa_snprintf(t, sizeof(t), "%u", i->n_used);
437 if (short_list_format) {
438 printf("%u\t%s\t%s\t\n", i->index, i->name, i->argument ? i->argument : "");
439 return;
442 printf(_("Module #%u\n"
443 "\tName: %s\n"
444 "\tArgument: %s\n"
445 "\tUsage counter: %s\n"
446 "\tProperties:\n\t\t%s\n"),
447 i->index,
448 i->name,
449 i->argument ? i->argument : "",
450 i->n_used != PA_INVALID_INDEX ? t : _("n/a"),
451 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
453 pa_xfree(pl);
456 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
457 char t[32];
458 char *pl;
460 if (is_last < 0) {
461 pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
462 quit(1);
463 return;
466 if (is_last) {
467 complete_action();
468 return;
471 pa_assert(i);
473 if (nl && !short_list_format)
474 printf("\n");
475 nl = TRUE;
477 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
479 if (short_list_format) {
480 printf("%u\t%s\t%s\n",
481 i->index,
482 pa_strnull(i->driver),
483 pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
484 return;
487 printf(_("Client #%u\n"
488 "\tDriver: %s\n"
489 "\tOwner Module: %s\n"
490 "\tProperties:\n\t\t%s\n"),
491 i->index,
492 pa_strnull(i->driver),
493 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
494 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
496 pa_xfree(pl);
499 static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_last, void *userdata) {
500 char t[32];
501 char *pl;
503 if (is_last < 0) {
504 pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c)));
505 complete_action();
506 return;
509 if (is_last) {
510 complete_action();
511 return;
514 pa_assert(i);
516 if (nl && !short_list_format)
517 printf("\n");
518 nl = TRUE;
520 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
522 if (short_list_format) {
523 printf("%u\t%s\t%s\n", i->index, i->name, pa_strnull(i->driver));
524 return;
527 printf(_("Card #%u\n"
528 "\tName: %s\n"
529 "\tDriver: %s\n"
530 "\tOwner Module: %s\n"
531 "\tProperties:\n\t\t%s\n"),
532 i->index,
533 i->name,
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"));
538 if (i->profiles) {
539 pa_card_profile_info *p;
541 printf(_("\tProfiles:\n"));
542 for (p = i->profiles; p->name; p++)
543 printf("\t\t%s: %s (sinks: %u, sources: %u, priority. %u)\n", p->name, p->description, p->n_sinks, p->n_sources, p->priority);
546 if (i->active_profile)
547 printf(_("\tActive Profile: %s\n"),
548 i->active_profile->name);
550 pa_xfree(pl);
553 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
554 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];
555 char *pl;
557 if (is_last < 0) {
558 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
559 quit(1);
560 return;
563 if (is_last) {
564 complete_action();
565 return;
568 pa_assert(i);
570 if (nl && !short_list_format)
571 printf("\n");
572 nl = TRUE;
574 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
575 pa_snprintf(k, sizeof(k), "%u", i->client);
577 if (short_list_format) {
578 printf("%u\t%u\t%s\t%s\t%s\n",
579 i->index,
580 i->sink,
581 i->client != PA_INVALID_INDEX ? k : "-",
582 pa_strnull(i->driver),
583 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
584 return;
587 printf(_("Sink Input #%u\n"
588 "\tDriver: %s\n"
589 "\tOwner Module: %s\n"
590 "\tClient: %s\n"
591 "\tSink: %u\n"
592 "\tSample Specification: %s\n"
593 "\tChannel Map: %s\n"
594 "\tMute: %s\n"
595 "\tVolume: %s\n"
596 "\t %s\n"
597 "\t balance %0.2f\n"
598 "\tBuffer Latency: %0.0f usec\n"
599 "\tSink Latency: %0.0f usec\n"
600 "\tResample method: %s\n"
601 "\tProperties:\n\t\t%s\n"),
602 i->index,
603 pa_strnull(i->driver),
604 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
605 i->client != PA_INVALID_INDEX ? k : _("n/a"),
606 i->sink,
607 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
608 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
609 pa_yes_no(i->mute),
610 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
611 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
612 pa_cvolume_get_balance(&i->volume, &i->channel_map),
613 (double) i->buffer_usec,
614 (double) i->sink_usec,
615 i->resample_method ? i->resample_method : _("n/a"),
616 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
618 pa_xfree(pl);
621 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
622 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
623 char *pl;
625 if (is_last < 0) {
626 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
627 quit(1);
628 return;
631 if (is_last) {
632 complete_action();
633 return;
636 pa_assert(i);
638 if (nl && !short_list_format)
639 printf("\n");
640 nl = TRUE;
643 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
644 pa_snprintf(k, sizeof(k), "%u", i->client);
646 if (short_list_format) {
647 printf("%u\t%u\t%s\t%s\t%s\n",
648 i->index,
649 i->source,
650 i->client != PA_INVALID_INDEX ? k : "-",
651 pa_strnull(i->driver),
652 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
653 return;
656 printf(_("Source Output #%u\n"
657 "\tDriver: %s\n"
658 "\tOwner Module: %s\n"
659 "\tClient: %s\n"
660 "\tSource: %u\n"
661 "\tSample Specification: %s\n"
662 "\tChannel Map: %s\n"
663 "\tBuffer Latency: %0.0f usec\n"
664 "\tSource Latency: %0.0f usec\n"
665 "\tResample method: %s\n"
666 "\tProperties:\n\t\t%s\n"),
667 i->index,
668 pa_strnull(i->driver),
669 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
670 i->client != PA_INVALID_INDEX ? k : _("n/a"),
671 i->source,
672 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
673 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
674 (double) i->buffer_usec,
675 (double) i->source_usec,
676 i->resample_method ? i->resample_method : _("n/a"),
677 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
679 pa_xfree(pl);
682 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
683 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];
684 char *pl;
686 if (is_last < 0) {
687 pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
688 quit(1);
689 return;
692 if (is_last) {
693 complete_action();
694 return;
697 pa_assert(i);
699 if (nl && !short_list_format)
700 printf("\n");
701 nl = TRUE;
703 pa_bytes_snprint(t, sizeof(t), i->bytes);
705 if (short_list_format) {
706 printf("%u\t%s\t%s\t%0.3f\n",
707 i->index,
708 i->name,
709 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "-",
710 (double) i->duration/1000000.0);
711 return;
714 printf(_("Sample #%u\n"
715 "\tName: %s\n"
716 "\tSample Specification: %s\n"
717 "\tChannel Map: %s\n"
718 "\tVolume: %s\n"
719 "\t %s\n"
720 "\t balance %0.2f\n"
721 "\tDuration: %0.1fs\n"
722 "\tSize: %s\n"
723 "\tLazy: %s\n"
724 "\tFilename: %s\n"
725 "\tProperties:\n\t\t%s\n"),
726 i->index,
727 i->name,
728 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
729 pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
730 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
731 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
732 pa_cvolume_get_balance(&i->volume, &i->channel_map),
733 (double) i->duration/1000000.0,
735 pa_yes_no(i->lazy),
736 i->filename ? i->filename : _("n/a"),
737 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
739 pa_xfree(pl);
742 static void simple_callback(pa_context *c, int success, void *userdata) {
743 if (!success) {
744 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
745 quit(1);
746 return;
749 complete_action();
752 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
753 if (idx == PA_INVALID_INDEX) {
754 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
755 quit(1);
756 return;
759 printf("%u\n", idx);
761 complete_action();
764 static void volume_relative_adjust(pa_cvolume *cv) {
765 pa_assert((volume_flags & VOL_RELATIVE) == VOL_RELATIVE);
767 /* Relative volume change is additive in case of UINT or PERCENT
768 * and multiplicative for LINEAR or DECIBEL */
769 if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
770 pa_volume_t v = pa_cvolume_avg(cv);
771 v = v + volume < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + volume - PA_VOLUME_NORM;
772 pa_cvolume_set(cv, 1, v);
774 if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) {
775 pa_sw_cvolume_multiply_scalar(cv, cv, volume);
779 static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
780 pa_cvolume cv;
782 if (is_last < 0) {
783 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
784 quit(1);
785 return;
788 if (is_last)
789 return;
791 pa_assert(i);
793 cv = i->volume;
794 volume_relative_adjust(&cv);
795 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
798 static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
799 pa_cvolume cv;
801 if (is_last < 0) {
802 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
803 quit(1);
804 return;
807 if (is_last)
808 return;
810 pa_assert(i);
812 cv = i->volume;
813 volume_relative_adjust(&cv);
814 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
817 static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
818 pa_cvolume cv;
820 if (is_last < 0) {
821 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
822 quit(1);
823 return;
826 if (is_last)
827 return;
829 pa_assert(i);
831 cv = i->volume;
832 volume_relative_adjust(&cv);
833 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
836 static void stream_state_callback(pa_stream *s, void *userdata) {
837 pa_assert(s);
839 switch (pa_stream_get_state(s)) {
840 case PA_STREAM_CREATING:
841 case PA_STREAM_READY:
842 break;
844 case PA_STREAM_TERMINATED:
845 drain();
846 break;
848 case PA_STREAM_FAILED:
849 default:
850 pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
851 quit(1);
855 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
856 sf_count_t l;
857 float *d;
858 pa_assert(s && length && sndfile);
860 d = pa_xmalloc(length);
862 pa_assert(sample_length >= length);
863 l = (sf_count_t) (length/pa_frame_size(&sample_spec));
865 if ((sf_readf_float(sndfile, d, l)) != l) {
866 pa_xfree(d);
867 pa_log(_("Premature end of file"));
868 quit(1);
869 return;
872 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
874 sample_length -= length;
876 if (sample_length <= 0) {
877 pa_stream_set_write_callback(sample_stream, NULL, NULL);
878 pa_stream_finish_upload(sample_stream);
882 static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) {
884 switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
886 case PA_SUBSCRIPTION_EVENT_NEW:
887 return _("new");
889 case PA_SUBSCRIPTION_EVENT_CHANGE:
890 return _("change");
892 case PA_SUBSCRIPTION_EVENT_REMOVE:
893 return _("remove");
896 return _("unknown");
899 static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) {
901 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
903 case PA_SUBSCRIPTION_EVENT_SINK:
904 return _("sink");
906 case PA_SUBSCRIPTION_EVENT_SOURCE:
907 return _("source");
909 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
910 return _("sink-input");
912 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
913 return _("source-output");
915 case PA_SUBSCRIPTION_EVENT_MODULE:
916 return _("module");
918 case PA_SUBSCRIPTION_EVENT_CLIENT:
919 return _("client");
921 case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
922 return _("sample-cache");
924 case PA_SUBSCRIPTION_EVENT_SERVER:
925 return _("server");
927 case PA_SUBSCRIPTION_EVENT_CARD:
928 return _("server");
931 return _("unknown");
934 static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
935 pa_assert(c);
937 printf(_("Event '%s' on %s #%u\n"),
938 subscription_event_type_to_string(t),
939 subscription_event_facility_to_string(t),
940 idx);
943 static void context_state_callback(pa_context *c, void *userdata) {
944 pa_assert(c);
945 switch (pa_context_get_state(c)) {
946 case PA_CONTEXT_CONNECTING:
947 case PA_CONTEXT_AUTHORIZING:
948 case PA_CONTEXT_SETTING_NAME:
949 break;
951 case PA_CONTEXT_READY:
952 switch (action) {
953 case STAT:
954 pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
955 break;
957 case INFO:
958 pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
959 break;
961 case PLAY_SAMPLE:
962 pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL));
963 break;
965 case REMOVE_SAMPLE:
966 pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
967 break;
969 case UPLOAD_SAMPLE:
970 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
971 pa_assert(sample_stream);
973 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
974 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
975 pa_stream_connect_upload(sample_stream, sample_length);
976 break;
978 case EXIT:
979 pa_operation_unref(pa_context_exit_daemon(c, simple_callback, NULL));
980 break;
982 case LIST:
983 if (list_type) {
984 if (pa_streq(list_type, "modules"))
985 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
986 else if (pa_streq(list_type, "sinks"))
987 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
988 else if (pa_streq(list_type, "sources"))
989 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
990 else if (pa_streq(list_type, "sink-inputs"))
991 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
992 else if (pa_streq(list_type, "source-outputs"))
993 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
994 else if (pa_streq(list_type, "clients"))
995 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
996 else if (pa_streq(list_type, "samples"))
997 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
998 else if (pa_streq(list_type, "cards"))
999 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
1000 else
1001 pa_assert_not_reached();
1002 } else {
1003 actions = 8;
1004 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
1005 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
1006 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
1007 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
1008 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
1009 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
1010 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
1011 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
1013 break;
1015 case MOVE_SINK_INPUT:
1016 pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL));
1017 break;
1019 case MOVE_SOURCE_OUTPUT:
1020 pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
1021 break;
1023 case LOAD_MODULE:
1024 pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
1025 break;
1027 case UNLOAD_MODULE:
1028 pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
1029 break;
1031 case SUSPEND_SINK:
1032 if (sink_name)
1033 pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
1034 else
1035 pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
1036 break;
1038 case SUSPEND_SOURCE:
1039 if (source_name)
1040 pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
1041 else
1042 pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
1043 break;
1045 case SET_CARD_PROFILE:
1046 pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
1047 break;
1049 case SET_SINK_PORT:
1050 pa_operation_unref(pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL));
1051 break;
1053 case SET_SOURCE_PORT:
1054 pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL));
1055 break;
1057 case SET_SINK_MUTE:
1058 pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL));
1059 break;
1061 case SET_SOURCE_MUTE:
1062 pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL));
1063 break;
1065 case SET_SINK_INPUT_MUTE:
1066 pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
1067 break;
1069 case SET_SINK_VOLUME:
1070 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1071 pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
1072 } else {
1073 pa_cvolume v;
1074 pa_cvolume_set(&v, 1, volume);
1075 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
1077 break;
1079 case SET_SOURCE_VOLUME:
1080 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1081 pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
1082 } else {
1083 pa_cvolume v;
1084 pa_cvolume_set(&v, 1, volume);
1085 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
1087 break;
1089 case SET_SINK_INPUT_VOLUME:
1090 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1091 pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
1092 } else {
1093 pa_cvolume v;
1094 pa_cvolume_set(&v, 1, volume);
1095 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
1097 break;
1099 case SUBSCRIBE:
1100 pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
1102 pa_operation_unref(pa_context_subscribe(
1104 PA_SUBSCRIPTION_MASK_SINK|
1105 PA_SUBSCRIPTION_MASK_SOURCE|
1106 PA_SUBSCRIPTION_MASK_SINK_INPUT|
1107 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
1108 PA_SUBSCRIPTION_MASK_MODULE|
1109 PA_SUBSCRIPTION_MASK_CLIENT|
1110 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
1111 PA_SUBSCRIPTION_MASK_SERVER|
1112 PA_SUBSCRIPTION_MASK_CARD,
1113 NULL,
1114 NULL));
1115 break;
1117 default:
1118 pa_assert_not_reached();
1120 break;
1122 case PA_CONTEXT_TERMINATED:
1123 quit(0);
1124 break;
1126 case PA_CONTEXT_FAILED:
1127 default:
1128 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
1129 quit(1);
1133 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
1134 pa_log(_("Got SIGINT, exiting."));
1135 quit(0);
1138 static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) {
1139 double v;
1140 char *vs;
1142 pa_assert(vol_spec);
1143 pa_assert(vol);
1144 pa_assert(vol_flags);
1146 vs = pa_xstrdup(vol_spec);
1148 *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;
1149 if (strchr(vs, '.'))
1150 *vol_flags |= VOL_LINEAR;
1151 if (pa_endswith(vs, "%")) {
1152 *vol_flags |= VOL_PERCENT;
1153 vs[strlen(vs)-1] = 0;
1155 if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) {
1156 *vol_flags |= VOL_DECIBEL;
1157 vs[strlen(vs)-2] = 0;
1160 if (pa_atod(vs, &v) < 0) {
1161 pa_log(_("Invalid volume specification"));
1162 pa_xfree(vs);
1163 return -1;
1166 pa_xfree(vs);
1168 if ((*vol_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1169 if ((*vol_flags & 0x0F) == VOL_UINT)
1170 v += (double) PA_VOLUME_NORM;
1171 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1172 v += 100.0;
1173 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1174 v += 1.0;
1176 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1177 v = v * (double) PA_VOLUME_NORM / 100;
1178 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1179 v = pa_sw_volume_from_linear(v);
1180 if ((*vol_flags & 0x0F) == VOL_DECIBEL)
1181 v = pa_sw_volume_from_dB(v);
1183 if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) {
1184 pa_log(_("Volume outside permissible range.\n"));
1185 return -1;
1188 *vol = (pa_volume_t) v;
1190 return 0;
1193 static void help(const char *argv0) {
1195 printf(_("%s [options] stat\n"
1196 "%s [options] info\n"
1197 "%s [options] list [short] [TYPE]\n"
1198 "%s [options] exit\n"
1199 "%s [options] upload-sample FILENAME [NAME]\n"
1200 "%s [options] play-sample NAME [SINK]\n"
1201 "%s [options] remove-sample NAME\n"
1202 "%s [options] move-sink-input SINKINPUT SINK\n"
1203 "%s [options] move-source-output SOURCEOUTPUT SOURCE\n"
1204 "%s [options] load-module NAME [ARGS ...]\n"
1205 "%s [options] unload-module MODULE\n"
1206 "%s [options] suspend-sink SINK 1|0\n"
1207 "%s [options] suspend-source SOURCE 1|0\n"
1208 "%s [options] set-card-profile CARD PROFILE\n"
1209 "%s [options] set-sink-port SINK PORT\n"
1210 "%s [options] set-source-port SOURCE PORT\n"
1211 "%s [options] set-sink-volume SINK VOLUME\n"
1212 "%s [options] set-source-volume SOURCE VOLUME\n"
1213 "%s [options] set-sink-input-volume SINKINPUT VOLUME\n"
1214 "%s [options] set-sink-mute SINK 1|0\n"
1215 "%s [options] set-source-mute SOURCE 1|0\n"
1216 "%s [options] set-sink-input-mute SINKINPUT 1|0\n"
1217 "%s [options] subscribe\n\n"
1218 " -h, --help Show this help\n"
1219 " --version Show version\n\n"
1220 " -s, --server=SERVER The name of the server to connect to\n"
1221 " -n, --client-name=NAME How to call this client on the server\n"),
1222 argv0, argv0, argv0, argv0, argv0,
1223 argv0, argv0, argv0, argv0, argv0,
1224 argv0, argv0, argv0, argv0, argv0,
1225 argv0, argv0, argv0, argv0, argv0,
1226 argv0, argv0, argv0);
1229 enum {
1230 ARG_VERSION = 256
1233 int main(int argc, char *argv[]) {
1234 pa_mainloop *m = NULL;
1235 int ret = 1, c;
1236 char *server = NULL, *bn;
1238 static const struct option long_options[] = {
1239 {"server", 1, NULL, 's'},
1240 {"client-name", 1, NULL, 'n'},
1241 {"version", 0, NULL, ARG_VERSION},
1242 {"help", 0, NULL, 'h'},
1243 {NULL, 0, NULL, 0}
1246 setlocale(LC_ALL, "");
1247 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
1249 bn = pa_path_get_filename(argv[0]);
1251 proplist = pa_proplist_new();
1253 while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
1254 switch (c) {
1255 case 'h' :
1256 help(bn);
1257 ret = 0;
1258 goto quit;
1260 case ARG_VERSION:
1261 printf(_("pactl %s\n"
1262 "Compiled with libpulse %s\n"
1263 "Linked with libpulse %s\n"),
1264 PACKAGE_VERSION,
1265 pa_get_headers_version(),
1266 pa_get_library_version());
1267 ret = 0;
1268 goto quit;
1270 case 's':
1271 pa_xfree(server);
1272 server = pa_xstrdup(optarg);
1273 break;
1275 case 'n': {
1276 char *t;
1278 if (!(t = pa_locale_to_utf8(optarg)) ||
1279 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
1281 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
1282 pa_xfree(t);
1283 goto quit;
1286 pa_xfree(t);
1287 break;
1290 default:
1291 goto quit;
1295 if (optind < argc) {
1296 if (pa_streq(argv[optind], "stat"))
1297 action = STAT;
1299 else if (pa_streq(argv[optind], "info"))
1300 action = INFO;
1302 else if (pa_streq(argv[optind], "exit"))
1303 action = EXIT;
1305 else if (pa_streq(argv[optind], "list")) {
1306 action = LIST;
1308 for (int i = optind+1; i < argc; i++){
1309 if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
1310 pa_streq(argv[i], "sinks") || pa_streq(argv[i], "sink-inputs") ||
1311 pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
1312 pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
1313 list_type = pa_xstrdup(argv[i]);
1314 } else if (pa_streq(argv[i], "short")) {
1315 short_list_format = TRUE;
1316 } else {
1317 pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
1318 goto quit;
1322 } else if (pa_streq(argv[optind], "upload-sample")) {
1323 struct SF_INFO sfi;
1324 action = UPLOAD_SAMPLE;
1326 if (optind+1 >= argc) {
1327 pa_log(_("Please specify a sample file to load"));
1328 goto quit;
1331 if (optind+2 < argc)
1332 sample_name = pa_xstrdup(argv[optind+2]);
1333 else {
1334 char *f = pa_path_get_filename(argv[optind+1]);
1335 sample_name = pa_xstrndup(f, strcspn(f, "."));
1338 pa_zero(sfi);
1339 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
1340 pa_log(_("Failed to open sound file."));
1341 goto quit;
1344 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1345 pa_log(_("Failed to determine sample specification from file."));
1346 goto quit;
1348 sample_spec.format = PA_SAMPLE_FLOAT32;
1350 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1351 if (sample_spec.channels > 2)
1352 pa_log(_("Warning: Failed to determine sample specification from file."));
1353 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1356 pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
1357 sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
1359 } else if (pa_streq(argv[optind], "play-sample")) {
1360 action = PLAY_SAMPLE;
1361 if (argc != optind+2 && argc != optind+3) {
1362 pa_log(_("You have to specify a sample name to play"));
1363 goto quit;
1366 sample_name = pa_xstrdup(argv[optind+1]);
1368 if (optind+2 < argc)
1369 sink_name = pa_xstrdup(argv[optind+2]);
1371 } else if (pa_streq(argv[optind], "remove-sample")) {
1372 action = REMOVE_SAMPLE;
1373 if (argc != optind+2) {
1374 pa_log(_("You have to specify a sample name to remove"));
1375 goto quit;
1378 sample_name = pa_xstrdup(argv[optind+1]);
1380 } else if (pa_streq(argv[optind], "move-sink-input")) {
1381 action = MOVE_SINK_INPUT;
1382 if (argc != optind+3) {
1383 pa_log(_("You have to specify a sink input index and a sink"));
1384 goto quit;
1387 sink_input_idx = (uint32_t) atoi(argv[optind+1]);
1388 sink_name = pa_xstrdup(argv[optind+2]);
1390 } else if (pa_streq(argv[optind], "move-source-output")) {
1391 action = MOVE_SOURCE_OUTPUT;
1392 if (argc != optind+3) {
1393 pa_log(_("You have to specify a source output index and a source"));
1394 goto quit;
1397 source_output_idx = (uint32_t) atoi(argv[optind+1]);
1398 source_name = pa_xstrdup(argv[optind+2]);
1400 } else if (pa_streq(argv[optind], "load-module")) {
1401 int i;
1402 size_t n = 0;
1403 char *p;
1405 action = LOAD_MODULE;
1407 if (argc <= optind+1) {
1408 pa_log(_("You have to specify a module name and arguments."));
1409 goto quit;
1412 module_name = argv[optind+1];
1414 for (i = optind+2; i < argc; i++)
1415 n += strlen(argv[i])+1;
1417 if (n > 0) {
1418 p = module_args = pa_xmalloc(n);
1420 for (i = optind+2; i < argc; i++)
1421 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
1424 } else if (pa_streq(argv[optind], "unload-module")) {
1425 action = UNLOAD_MODULE;
1427 if (argc != optind+2) {
1428 pa_log(_("You have to specify a module index"));
1429 goto quit;
1432 module_index = (uint32_t) atoi(argv[optind+1]);
1434 } else if (pa_streq(argv[optind], "suspend-sink")) {
1435 action = SUSPEND_SINK;
1437 if (argc > optind+3 || optind+1 >= argc) {
1438 pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
1439 goto quit;
1442 suspend = pa_parse_boolean(argv[argc-1]);
1444 if (argc > optind+2)
1445 sink_name = pa_xstrdup(argv[optind+1]);
1447 } else if (pa_streq(argv[optind], "suspend-source")) {
1448 action = SUSPEND_SOURCE;
1450 if (argc > optind+3 || optind+1 >= argc) {
1451 pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
1452 goto quit;
1455 suspend = pa_parse_boolean(argv[argc-1]);
1457 if (argc > optind+2)
1458 source_name = pa_xstrdup(argv[optind+1]);
1459 } else if (pa_streq(argv[optind], "set-card-profile")) {
1460 action = SET_CARD_PROFILE;
1462 if (argc != optind+3) {
1463 pa_log(_("You have to specify a card name/index and a profile name"));
1464 goto quit;
1467 card_name = pa_xstrdup(argv[optind+1]);
1468 profile_name = pa_xstrdup(argv[optind+2]);
1470 } else if (pa_streq(argv[optind], "set-sink-port")) {
1471 action = SET_SINK_PORT;
1473 if (argc != optind+3) {
1474 pa_log(_("You have to specify a sink name/index and a port name"));
1475 goto quit;
1478 sink_name = pa_xstrdup(argv[optind+1]);
1479 port_name = pa_xstrdup(argv[optind+2]);
1481 } else if (pa_streq(argv[optind], "set-source-port")) {
1482 action = SET_SOURCE_PORT;
1484 if (argc != optind+3) {
1485 pa_log(_("You have to specify a source name/index and a port name"));
1486 goto quit;
1489 source_name = pa_xstrdup(argv[optind+1]);
1490 port_name = pa_xstrdup(argv[optind+2]);
1492 } else if (pa_streq(argv[optind], "set-sink-volume")) {
1493 action = SET_SINK_VOLUME;
1495 if (argc != optind+3) {
1496 pa_log(_("You have to specify a sink name/index and a volume"));
1497 goto quit;
1500 sink_name = pa_xstrdup(argv[optind+1]);
1502 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1503 goto quit;
1505 } else if (pa_streq(argv[optind], "set-source-volume")) {
1506 action = SET_SOURCE_VOLUME;
1508 if (argc != optind+3) {
1509 pa_log(_("You have to specify a source name/index and a volume"));
1510 goto quit;
1513 source_name = pa_xstrdup(argv[optind+1]);
1515 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1516 goto quit;
1518 } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
1519 action = SET_SINK_INPUT_VOLUME;
1521 if (argc != optind+3) {
1522 pa_log(_("You have to specify a sink input index and a volume"));
1523 goto quit;
1526 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1527 pa_log(_("Invalid sink input index"));
1528 goto quit;
1531 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1532 goto quit;
1534 } else if (pa_streq(argv[optind], "set-sink-mute")) {
1535 int b;
1536 action = SET_SINK_MUTE;
1538 if (argc != optind+3) {
1539 pa_log(_("You have to specify a sink name/index and a mute boolean"));
1540 goto quit;
1543 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1544 pa_log(_("Invalid mute specification"));
1545 goto quit;
1548 sink_name = pa_xstrdup(argv[optind+1]);
1549 mute = b;
1551 } else if (pa_streq(argv[optind], "set-source-mute")) {
1552 int b;
1553 action = SET_SOURCE_MUTE;
1555 if (argc != optind+3) {
1556 pa_log(_("You have to specify a source name/index and a mute boolean"));
1557 goto quit;
1560 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1561 pa_log(_("Invalid mute specification"));
1562 goto quit;
1565 source_name = pa_xstrdup(argv[optind+1]);
1566 mute = b;
1568 } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
1569 int b;
1570 action = SET_SINK_INPUT_MUTE;
1572 if (argc != optind+3) {
1573 pa_log(_("You have to specify a sink input index and a mute boolean"));
1574 goto quit;
1577 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1578 pa_log(_("Invalid sink input index specification"));
1579 goto quit;
1582 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1583 pa_log(_("Invalid mute specification"));
1584 goto quit;
1587 mute = b;
1589 } else if (pa_streq(argv[optind], "subscribe"))
1591 action = SUBSCRIBE;
1593 else if (pa_streq(argv[optind], "help")) {
1594 help(bn);
1595 ret = 0;
1596 goto quit;
1600 if (action == NONE) {
1601 pa_log(_("No valid command specified."));
1602 goto quit;
1605 if (!(m = pa_mainloop_new())) {
1606 pa_log(_("pa_mainloop_new() failed."));
1607 goto quit;
1610 mainloop_api = pa_mainloop_get_api(m);
1612 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1613 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1614 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1615 pa_disable_sigpipe();
1617 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1618 pa_log(_("pa_context_new() failed."));
1619 goto quit;
1622 pa_context_set_state_callback(context, context_state_callback, NULL);
1623 if (pa_context_connect(context, server, 0, NULL) < 0) {
1624 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1625 goto quit;
1628 if (pa_mainloop_run(m, &ret) < 0) {
1629 pa_log(_("pa_mainloop_run() failed."));
1630 goto quit;
1633 quit:
1634 if (sample_stream)
1635 pa_stream_unref(sample_stream);
1637 if (context)
1638 pa_context_unref(context);
1640 if (m) {
1641 pa_signal_done();
1642 pa_mainloop_free(m);
1645 pa_xfree(server);
1646 pa_xfree(list_type);
1647 pa_xfree(sample_name);
1648 pa_xfree(sink_name);
1649 pa_xfree(source_name);
1650 pa_xfree(module_args);
1651 pa_xfree(card_name);
1652 pa_xfree(profile_name);
1653 pa_xfree(port_name);
1655 if (sndfile)
1656 sf_close(sndfile);
1658 if (proplist)
1659 pa_proplist_free(proplist);
1661 return ret;