suspend-on-idle: Trigger mempool vacuuming
[pulseaudio-mirror.git] / src / utils / pactl.c
blob7be7049f24938b8f6f99f8b38fc70bf88588e36c
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 f[PA_FORMAT_INFO_SNPRINT_MAX];
227 char *pl;
229 if (is_last < 0) {
230 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
231 quit(1);
232 return;
235 if (is_last) {
236 complete_action();
237 return;
240 pa_assert(i);
242 if (nl && !short_list_format)
243 printf("\n");
244 nl = TRUE;
246 if (short_list_format) {
247 printf("%u\t%s\t%s\t%s\t%s\n",
248 i->index,
249 i->name,
250 pa_strnull(i->driver),
251 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
252 state_table[1+i->state]);
253 return;
256 printf(_("Sink #%u\n"
257 "\tState: %s\n"
258 "\tName: %s\n"
259 "\tDescription: %s\n"
260 "\tDriver: %s\n"
261 "\tSample Specification: %s\n"
262 "\tChannel Map: %s\n"
263 "\tOwner Module: %u\n"
264 "\tMute: %s\n"
265 "\tVolume: %s%s%s\n"
266 "\t balance %0.2f\n"
267 "\tBase Volume: %s%s%s\n"
268 "\tMonitor Source: %s\n"
269 "\tLatency: %0.0f usec, configured %0.0f usec\n"
270 "\tFlags: %s%s%s%s%s%s\n"
271 "\tProperties:\n\t\t%s\n"),
272 i->index,
273 state_table[1+i->state],
274 i->name,
275 pa_strnull(i->description),
276 pa_strnull(i->driver),
277 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
278 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
279 i->owner_module,
280 pa_yes_no(i->mute),
281 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
282 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
283 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
284 pa_cvolume_get_balance(&i->volume, &i->channel_map),
285 pa_volume_snprint(v, sizeof(v), i->base_volume),
286 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
287 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
288 pa_strnull(i->monitor_source_name),
289 (double) i->latency, (double) i->configured_latency,
290 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
291 i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
292 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
293 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
294 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
295 i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
296 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
298 pa_xfree(pl);
300 if (i->ports) {
301 pa_sink_port_info **p;
303 printf(_("\tPorts:\n"));
304 for (p = i->ports; *p; p++)
305 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
308 if (i->active_port)
309 printf(_("\tActive Port: %s\n"),
310 i->active_port->name);
312 if (i->formats) {
313 uint8_t j;
315 printf(_("\tFormats:\n"));
316 for (j = 0; j < i->n_formats; j++)
317 printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j]));
321 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
323 static const char *state_table[] = {
324 [1+PA_SOURCE_INVALID_STATE] = "n/a",
325 [1+PA_SOURCE_RUNNING] = "RUNNING",
326 [1+PA_SOURCE_IDLE] = "IDLE",
327 [1+PA_SOURCE_SUSPENDED] = "SUSPENDED"
330 char
331 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
332 cv[PA_CVOLUME_SNPRINT_MAX],
333 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
334 v[PA_VOLUME_SNPRINT_MAX],
335 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
336 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
337 char *pl;
339 if (is_last < 0) {
340 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
341 quit(1);
342 return;
345 if (is_last) {
346 complete_action();
347 return;
350 pa_assert(i);
352 if (nl && !short_list_format)
353 printf("\n");
354 nl = TRUE;
356 if (short_list_format) {
357 printf("%u\t%s\t%s\t%s\t%s\n",
358 i->index,
359 i->name,
360 pa_strnull(i->driver),
361 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
362 state_table[1+i->state]);
363 return;
366 printf(_("Source #%u\n"
367 "\tState: %s\n"
368 "\tName: %s\n"
369 "\tDescription: %s\n"
370 "\tDriver: %s\n"
371 "\tSample Specification: %s\n"
372 "\tChannel Map: %s\n"
373 "\tOwner Module: %u\n"
374 "\tMute: %s\n"
375 "\tVolume: %s%s%s\n"
376 "\t balance %0.2f\n"
377 "\tBase Volume: %s%s%s\n"
378 "\tMonitor of Sink: %s\n"
379 "\tLatency: %0.0f usec, configured %0.0f usec\n"
380 "\tFlags: %s%s%s%s%s%s\n"
381 "\tProperties:\n\t\t%s\n"),
382 i->index,
383 state_table[1+i->state],
384 i->name,
385 pa_strnull(i->description),
386 pa_strnull(i->driver),
387 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
388 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
389 i->owner_module,
390 pa_yes_no(i->mute),
391 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
392 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
393 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
394 pa_cvolume_get_balance(&i->volume, &i->channel_map),
395 pa_volume_snprint(v, sizeof(v), i->base_volume),
396 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
397 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
398 i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
399 (double) i->latency, (double) i->configured_latency,
400 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
401 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
402 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
403 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
404 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
405 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
406 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
408 pa_xfree(pl);
410 if (i->ports) {
411 pa_source_port_info **p;
413 printf(_("\tPorts:\n"));
414 for (p = i->ports; *p; p++)
415 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
418 if (i->active_port)
419 printf(_("\tActive Port: %s\n"),
420 i->active_port->name);
423 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
424 char t[32];
425 char *pl;
427 if (is_last < 0) {
428 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
429 quit(1);
430 return;
433 if (is_last) {
434 complete_action();
435 return;
438 pa_assert(i);
440 if (nl && !short_list_format)
441 printf("\n");
442 nl = TRUE;
444 pa_snprintf(t, sizeof(t), "%u", i->n_used);
446 if (short_list_format) {
447 printf("%u\t%s\t%s\t\n", i->index, i->name, i->argument ? i->argument : "");
448 return;
451 printf(_("Module #%u\n"
452 "\tName: %s\n"
453 "\tArgument: %s\n"
454 "\tUsage counter: %s\n"
455 "\tProperties:\n\t\t%s\n"),
456 i->index,
457 i->name,
458 i->argument ? i->argument : "",
459 i->n_used != PA_INVALID_INDEX ? t : _("n/a"),
460 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
462 pa_xfree(pl);
465 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
466 char t[32];
467 char *pl;
469 if (is_last < 0) {
470 pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
471 quit(1);
472 return;
475 if (is_last) {
476 complete_action();
477 return;
480 pa_assert(i);
482 if (nl && !short_list_format)
483 printf("\n");
484 nl = TRUE;
486 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
488 if (short_list_format) {
489 printf("%u\t%s\t%s\n",
490 i->index,
491 pa_strnull(i->driver),
492 pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
493 return;
496 printf(_("Client #%u\n"
497 "\tDriver: %s\n"
498 "\tOwner Module: %s\n"
499 "\tProperties:\n\t\t%s\n"),
500 i->index,
501 pa_strnull(i->driver),
502 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
503 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
505 pa_xfree(pl);
508 static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_last, void *userdata) {
509 char t[32];
510 char *pl;
512 if (is_last < 0) {
513 pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c)));
514 complete_action();
515 return;
518 if (is_last) {
519 complete_action();
520 return;
523 pa_assert(i);
525 if (nl && !short_list_format)
526 printf("\n");
527 nl = TRUE;
529 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
531 if (short_list_format) {
532 printf("%u\t%s\t%s\n", i->index, i->name, pa_strnull(i->driver));
533 return;
536 printf(_("Card #%u\n"
537 "\tName: %s\n"
538 "\tDriver: %s\n"
539 "\tOwner Module: %s\n"
540 "\tProperties:\n\t\t%s\n"),
541 i->index,
542 i->name,
543 pa_strnull(i->driver),
544 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
545 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
547 if (i->profiles) {
548 pa_card_profile_info *p;
550 printf(_("\tProfiles:\n"));
551 for (p = i->profiles; p->name; p++)
552 printf("\t\t%s: %s (sinks: %u, sources: %u, priority. %u)\n", p->name, p->description, p->n_sinks, p->n_sources, p->priority);
555 if (i->active_profile)
556 printf(_("\tActive Profile: %s\n"),
557 i->active_profile->name);
559 pa_xfree(pl);
562 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
563 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];
564 char *pl;
566 if (is_last < 0) {
567 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
568 quit(1);
569 return;
572 if (is_last) {
573 complete_action();
574 return;
577 pa_assert(i);
579 if (nl && !short_list_format)
580 printf("\n");
581 nl = TRUE;
583 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
584 pa_snprintf(k, sizeof(k), "%u", i->client);
586 if (short_list_format) {
587 printf("%u\t%u\t%s\t%s\t%s\n",
588 i->index,
589 i->sink,
590 i->client != PA_INVALID_INDEX ? k : "-",
591 pa_strnull(i->driver),
592 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
593 return;
596 printf(_("Sink Input #%u\n"
597 "\tDriver: %s\n"
598 "\tOwner Module: %s\n"
599 "\tClient: %s\n"
600 "\tSink: %u\n"
601 "\tSample Specification: %s\n"
602 "\tChannel Map: %s\n"
603 "\tFormat: %s\n"
604 "\tMute: %s\n"
605 "\tVolume: %s\n"
606 "\t %s\n"
607 "\t balance %0.2f\n"
608 "\tBuffer Latency: %0.0f usec\n"
609 "\tSink Latency: %0.0f usec\n"
610 "\tResample method: %s\n"
611 "\tProperties:\n\t\t%s\n"),
612 i->index,
613 pa_strnull(i->driver),
614 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
615 i->client != PA_INVALID_INDEX ? k : _("n/a"),
616 i->sink,
617 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
618 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
619 pa_format_info_snprint(f, sizeof(f), i->format),
620 pa_yes_no(i->mute),
621 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
622 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
623 pa_cvolume_get_balance(&i->volume, &i->channel_map),
624 (double) i->buffer_usec,
625 (double) i->sink_usec,
626 i->resample_method ? i->resample_method : _("n/a"),
627 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
629 pa_xfree(pl);
632 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
633 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
634 char *pl;
636 if (is_last < 0) {
637 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
638 quit(1);
639 return;
642 if (is_last) {
643 complete_action();
644 return;
647 pa_assert(i);
649 if (nl && !short_list_format)
650 printf("\n");
651 nl = TRUE;
654 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
655 pa_snprintf(k, sizeof(k), "%u", i->client);
657 if (short_list_format) {
658 printf("%u\t%u\t%s\t%s\t%s\n",
659 i->index,
660 i->source,
661 i->client != PA_INVALID_INDEX ? k : "-",
662 pa_strnull(i->driver),
663 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
664 return;
667 printf(_("Source Output #%u\n"
668 "\tDriver: %s\n"
669 "\tOwner Module: %s\n"
670 "\tClient: %s\n"
671 "\tSource: %u\n"
672 "\tSample Specification: %s\n"
673 "\tChannel Map: %s\n"
674 "\tBuffer Latency: %0.0f usec\n"
675 "\tSource Latency: %0.0f usec\n"
676 "\tResample method: %s\n"
677 "\tProperties:\n\t\t%s\n"),
678 i->index,
679 pa_strnull(i->driver),
680 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
681 i->client != PA_INVALID_INDEX ? k : _("n/a"),
682 i->source,
683 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
684 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
685 (double) i->buffer_usec,
686 (double) i->source_usec,
687 i->resample_method ? i->resample_method : _("n/a"),
688 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
690 pa_xfree(pl);
693 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
694 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];
695 char *pl;
697 if (is_last < 0) {
698 pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
699 quit(1);
700 return;
703 if (is_last) {
704 complete_action();
705 return;
708 pa_assert(i);
710 if (nl && !short_list_format)
711 printf("\n");
712 nl = TRUE;
714 pa_bytes_snprint(t, sizeof(t), i->bytes);
716 if (short_list_format) {
717 printf("%u\t%s\t%s\t%0.3f\n",
718 i->index,
719 i->name,
720 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "-",
721 (double) i->duration/1000000.0);
722 return;
725 printf(_("Sample #%u\n"
726 "\tName: %s\n"
727 "\tSample Specification: %s\n"
728 "\tChannel Map: %s\n"
729 "\tVolume: %s\n"
730 "\t %s\n"
731 "\t balance %0.2f\n"
732 "\tDuration: %0.1fs\n"
733 "\tSize: %s\n"
734 "\tLazy: %s\n"
735 "\tFilename: %s\n"
736 "\tProperties:\n\t\t%s\n"),
737 i->index,
738 i->name,
739 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
740 pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
741 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
742 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
743 pa_cvolume_get_balance(&i->volume, &i->channel_map),
744 (double) i->duration/1000000.0,
746 pa_yes_no(i->lazy),
747 i->filename ? i->filename : _("n/a"),
748 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
750 pa_xfree(pl);
753 static void simple_callback(pa_context *c, int success, void *userdata) {
754 if (!success) {
755 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
756 quit(1);
757 return;
760 complete_action();
763 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
764 if (idx == PA_INVALID_INDEX) {
765 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
766 quit(1);
767 return;
770 printf("%u\n", idx);
772 complete_action();
775 static void volume_relative_adjust(pa_cvolume *cv) {
776 pa_assert((volume_flags & VOL_RELATIVE) == VOL_RELATIVE);
778 /* Relative volume change is additive in case of UINT or PERCENT
779 * and multiplicative for LINEAR or DECIBEL */
780 if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
781 pa_volume_t v = pa_cvolume_avg(cv);
782 v = v + volume < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + volume - PA_VOLUME_NORM;
783 pa_cvolume_set(cv, 1, v);
785 if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) {
786 pa_sw_cvolume_multiply_scalar(cv, cv, volume);
790 static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
791 pa_cvolume cv;
793 if (is_last < 0) {
794 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
795 quit(1);
796 return;
799 if (is_last)
800 return;
802 pa_assert(i);
804 cv = i->volume;
805 volume_relative_adjust(&cv);
806 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
809 static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
810 pa_cvolume cv;
812 if (is_last < 0) {
813 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
814 quit(1);
815 return;
818 if (is_last)
819 return;
821 pa_assert(i);
823 cv = i->volume;
824 volume_relative_adjust(&cv);
825 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
828 static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
829 pa_cvolume cv;
831 if (is_last < 0) {
832 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
833 quit(1);
834 return;
837 if (is_last)
838 return;
840 pa_assert(i);
842 cv = i->volume;
843 volume_relative_adjust(&cv);
844 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
847 static void stream_state_callback(pa_stream *s, void *userdata) {
848 pa_assert(s);
850 switch (pa_stream_get_state(s)) {
851 case PA_STREAM_CREATING:
852 case PA_STREAM_READY:
853 break;
855 case PA_STREAM_TERMINATED:
856 drain();
857 break;
859 case PA_STREAM_FAILED:
860 default:
861 pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
862 quit(1);
866 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
867 sf_count_t l;
868 float *d;
869 pa_assert(s && length && sndfile);
871 d = pa_xmalloc(length);
873 pa_assert(sample_length >= length);
874 l = (sf_count_t) (length/pa_frame_size(&sample_spec));
876 if ((sf_readf_float(sndfile, d, l)) != l) {
877 pa_xfree(d);
878 pa_log(_("Premature end of file"));
879 quit(1);
880 return;
883 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
885 sample_length -= length;
887 if (sample_length <= 0) {
888 pa_stream_set_write_callback(sample_stream, NULL, NULL);
889 pa_stream_finish_upload(sample_stream);
893 static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) {
895 switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
897 case PA_SUBSCRIPTION_EVENT_NEW:
898 return _("new");
900 case PA_SUBSCRIPTION_EVENT_CHANGE:
901 return _("change");
903 case PA_SUBSCRIPTION_EVENT_REMOVE:
904 return _("remove");
907 return _("unknown");
910 static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) {
912 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
914 case PA_SUBSCRIPTION_EVENT_SINK:
915 return _("sink");
917 case PA_SUBSCRIPTION_EVENT_SOURCE:
918 return _("source");
920 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
921 return _("sink-input");
923 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
924 return _("source-output");
926 case PA_SUBSCRIPTION_EVENT_MODULE:
927 return _("module");
929 case PA_SUBSCRIPTION_EVENT_CLIENT:
930 return _("client");
932 case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
933 return _("sample-cache");
935 case PA_SUBSCRIPTION_EVENT_SERVER:
936 return _("server");
938 case PA_SUBSCRIPTION_EVENT_CARD:
939 return _("server");
942 return _("unknown");
945 static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
946 pa_assert(c);
948 printf(_("Event '%s' on %s #%u\n"),
949 subscription_event_type_to_string(t),
950 subscription_event_facility_to_string(t),
951 idx);
954 static void context_state_callback(pa_context *c, void *userdata) {
955 pa_assert(c);
956 switch (pa_context_get_state(c)) {
957 case PA_CONTEXT_CONNECTING:
958 case PA_CONTEXT_AUTHORIZING:
959 case PA_CONTEXT_SETTING_NAME:
960 break;
962 case PA_CONTEXT_READY:
963 switch (action) {
964 case STAT:
965 pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
966 break;
968 case INFO:
969 pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
970 break;
972 case PLAY_SAMPLE:
973 pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL));
974 break;
976 case REMOVE_SAMPLE:
977 pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
978 break;
980 case UPLOAD_SAMPLE:
981 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
982 pa_assert(sample_stream);
984 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
985 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
986 pa_stream_connect_upload(sample_stream, sample_length);
987 break;
989 case EXIT:
990 pa_operation_unref(pa_context_exit_daemon(c, simple_callback, NULL));
991 break;
993 case LIST:
994 if (list_type) {
995 if (pa_streq(list_type, "modules"))
996 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
997 else if (pa_streq(list_type, "sinks"))
998 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
999 else if (pa_streq(list_type, "sources"))
1000 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
1001 else if (pa_streq(list_type, "sink-inputs"))
1002 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
1003 else if (pa_streq(list_type, "source-outputs"))
1004 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
1005 else if (pa_streq(list_type, "clients"))
1006 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
1007 else if (pa_streq(list_type, "samples"))
1008 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
1009 else if (pa_streq(list_type, "cards"))
1010 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
1011 else
1012 pa_assert_not_reached();
1013 } else {
1014 actions = 8;
1015 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
1016 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
1017 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
1018 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
1019 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
1020 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
1021 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
1022 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
1024 break;
1026 case MOVE_SINK_INPUT:
1027 pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL));
1028 break;
1030 case MOVE_SOURCE_OUTPUT:
1031 pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
1032 break;
1034 case LOAD_MODULE:
1035 pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
1036 break;
1038 case UNLOAD_MODULE:
1039 pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
1040 break;
1042 case SUSPEND_SINK:
1043 if (sink_name)
1044 pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
1045 else
1046 pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
1047 break;
1049 case SUSPEND_SOURCE:
1050 if (source_name)
1051 pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
1052 else
1053 pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
1054 break;
1056 case SET_CARD_PROFILE:
1057 pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
1058 break;
1060 case SET_SINK_PORT:
1061 pa_operation_unref(pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL));
1062 break;
1064 case SET_SOURCE_PORT:
1065 pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL));
1066 break;
1068 case SET_SINK_MUTE:
1069 pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL));
1070 break;
1072 case SET_SOURCE_MUTE:
1073 pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL));
1074 break;
1076 case SET_SINK_INPUT_MUTE:
1077 pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
1078 break;
1080 case SET_SINK_VOLUME:
1081 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1082 pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
1083 } else {
1084 pa_cvolume v;
1085 pa_cvolume_set(&v, 1, volume);
1086 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
1088 break;
1090 case SET_SOURCE_VOLUME:
1091 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1092 pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
1093 } else {
1094 pa_cvolume v;
1095 pa_cvolume_set(&v, 1, volume);
1096 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
1098 break;
1100 case SET_SINK_INPUT_VOLUME:
1101 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1102 pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
1103 } else {
1104 pa_cvolume v;
1105 pa_cvolume_set(&v, 1, volume);
1106 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
1108 break;
1110 case SUBSCRIBE:
1111 pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
1113 pa_operation_unref(pa_context_subscribe(
1115 PA_SUBSCRIPTION_MASK_SINK|
1116 PA_SUBSCRIPTION_MASK_SOURCE|
1117 PA_SUBSCRIPTION_MASK_SINK_INPUT|
1118 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
1119 PA_SUBSCRIPTION_MASK_MODULE|
1120 PA_SUBSCRIPTION_MASK_CLIENT|
1121 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
1122 PA_SUBSCRIPTION_MASK_SERVER|
1123 PA_SUBSCRIPTION_MASK_CARD,
1124 NULL,
1125 NULL));
1126 break;
1128 default:
1129 pa_assert_not_reached();
1131 break;
1133 case PA_CONTEXT_TERMINATED:
1134 quit(0);
1135 break;
1137 case PA_CONTEXT_FAILED:
1138 default:
1139 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
1140 quit(1);
1144 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
1145 pa_log(_("Got SIGINT, exiting."));
1146 quit(0);
1149 static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) {
1150 double v;
1151 char *vs;
1153 pa_assert(vol_spec);
1154 pa_assert(vol);
1155 pa_assert(vol_flags);
1157 vs = pa_xstrdup(vol_spec);
1159 *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;
1160 if (strchr(vs, '.'))
1161 *vol_flags |= VOL_LINEAR;
1162 if (pa_endswith(vs, "%")) {
1163 *vol_flags |= VOL_PERCENT;
1164 vs[strlen(vs)-1] = 0;
1166 if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) {
1167 *vol_flags |= VOL_DECIBEL;
1168 vs[strlen(vs)-2] = 0;
1171 if (pa_atod(vs, &v) < 0) {
1172 pa_log(_("Invalid volume specification"));
1173 pa_xfree(vs);
1174 return -1;
1177 pa_xfree(vs);
1179 if ((*vol_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1180 if ((*vol_flags & 0x0F) == VOL_UINT)
1181 v += (double) PA_VOLUME_NORM;
1182 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1183 v += 100.0;
1184 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1185 v += 1.0;
1187 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1188 v = v * (double) PA_VOLUME_NORM / 100;
1189 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1190 v = pa_sw_volume_from_linear(v);
1191 if ((*vol_flags & 0x0F) == VOL_DECIBEL)
1192 v = pa_sw_volume_from_dB(v);
1194 if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) {
1195 pa_log(_("Volume outside permissible range.\n"));
1196 return -1;
1199 *vol = (pa_volume_t) v;
1201 return 0;
1204 static void help(const char *argv0) {
1206 printf(_("%s [options] stat\n"
1207 "%s [options] info\n"
1208 "%s [options] list [short] [TYPE]\n"
1209 "%s [options] exit\n"
1210 "%s [options] upload-sample FILENAME [NAME]\n"
1211 "%s [options] play-sample NAME [SINK]\n"
1212 "%s [options] remove-sample NAME\n"
1213 "%s [options] move-sink-input SINKINPUT SINK\n"
1214 "%s [options] move-source-output SOURCEOUTPUT SOURCE\n"
1215 "%s [options] load-module NAME [ARGS ...]\n"
1216 "%s [options] unload-module MODULE\n"
1217 "%s [options] suspend-sink SINK 1|0\n"
1218 "%s [options] suspend-source SOURCE 1|0\n"
1219 "%s [options] set-card-profile CARD PROFILE\n"
1220 "%s [options] set-sink-port SINK PORT\n"
1221 "%s [options] set-source-port SOURCE PORT\n"
1222 "%s [options] set-sink-volume SINK VOLUME\n"
1223 "%s [options] set-source-volume SOURCE VOLUME\n"
1224 "%s [options] set-sink-input-volume SINKINPUT VOLUME\n"
1225 "%s [options] set-sink-mute SINK 1|0\n"
1226 "%s [options] set-source-mute SOURCE 1|0\n"
1227 "%s [options] set-sink-input-mute SINKINPUT 1|0\n"
1228 "%s [options] subscribe\n\n"
1229 " -h, --help Show this help\n"
1230 " --version Show version\n\n"
1231 " -s, --server=SERVER The name of the server to connect to\n"
1232 " -n, --client-name=NAME How to call this client on the server\n"),
1233 argv0, argv0, argv0, argv0, argv0,
1234 argv0, argv0, argv0, argv0, argv0,
1235 argv0, argv0, argv0, argv0, argv0,
1236 argv0, argv0, argv0, argv0, argv0,
1237 argv0, argv0, argv0);
1240 enum {
1241 ARG_VERSION = 256
1244 int main(int argc, char *argv[]) {
1245 pa_mainloop *m = NULL;
1246 int ret = 1, c;
1247 char *server = NULL, *bn;
1249 static const struct option long_options[] = {
1250 {"server", 1, NULL, 's'},
1251 {"client-name", 1, NULL, 'n'},
1252 {"version", 0, NULL, ARG_VERSION},
1253 {"help", 0, NULL, 'h'},
1254 {NULL, 0, NULL, 0}
1257 setlocale(LC_ALL, "");
1258 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
1260 bn = pa_path_get_filename(argv[0]);
1262 proplist = pa_proplist_new();
1264 while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
1265 switch (c) {
1266 case 'h' :
1267 help(bn);
1268 ret = 0;
1269 goto quit;
1271 case ARG_VERSION:
1272 printf(_("pactl %s\n"
1273 "Compiled with libpulse %s\n"
1274 "Linked with libpulse %s\n"),
1275 PACKAGE_VERSION,
1276 pa_get_headers_version(),
1277 pa_get_library_version());
1278 ret = 0;
1279 goto quit;
1281 case 's':
1282 pa_xfree(server);
1283 server = pa_xstrdup(optarg);
1284 break;
1286 case 'n': {
1287 char *t;
1289 if (!(t = pa_locale_to_utf8(optarg)) ||
1290 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
1292 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
1293 pa_xfree(t);
1294 goto quit;
1297 pa_xfree(t);
1298 break;
1301 default:
1302 goto quit;
1306 if (optind < argc) {
1307 if (pa_streq(argv[optind], "stat"))
1308 action = STAT;
1310 else if (pa_streq(argv[optind], "info"))
1311 action = INFO;
1313 else if (pa_streq(argv[optind], "exit"))
1314 action = EXIT;
1316 else if (pa_streq(argv[optind], "list")) {
1317 action = LIST;
1319 for (int i = optind+1; i < argc; i++){
1320 if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
1321 pa_streq(argv[i], "sinks") || pa_streq(argv[i], "sink-inputs") ||
1322 pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
1323 pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
1324 list_type = pa_xstrdup(argv[i]);
1325 } else if (pa_streq(argv[i], "short")) {
1326 short_list_format = TRUE;
1327 } else {
1328 pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
1329 goto quit;
1333 } else if (pa_streq(argv[optind], "upload-sample")) {
1334 struct SF_INFO sfi;
1335 action = UPLOAD_SAMPLE;
1337 if (optind+1 >= argc) {
1338 pa_log(_("Please specify a sample file to load"));
1339 goto quit;
1342 if (optind+2 < argc)
1343 sample_name = pa_xstrdup(argv[optind+2]);
1344 else {
1345 char *f = pa_path_get_filename(argv[optind+1]);
1346 sample_name = pa_xstrndup(f, strcspn(f, "."));
1349 pa_zero(sfi);
1350 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
1351 pa_log(_("Failed to open sound file."));
1352 goto quit;
1355 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1356 pa_log(_("Failed to determine sample specification from file."));
1357 goto quit;
1359 sample_spec.format = PA_SAMPLE_FLOAT32;
1361 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1362 if (sample_spec.channels > 2)
1363 pa_log(_("Warning: Failed to determine sample specification from file."));
1364 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1367 pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
1368 sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
1370 } else if (pa_streq(argv[optind], "play-sample")) {
1371 action = PLAY_SAMPLE;
1372 if (argc != optind+2 && argc != optind+3) {
1373 pa_log(_("You have to specify a sample name to play"));
1374 goto quit;
1377 sample_name = pa_xstrdup(argv[optind+1]);
1379 if (optind+2 < argc)
1380 sink_name = pa_xstrdup(argv[optind+2]);
1382 } else if (pa_streq(argv[optind], "remove-sample")) {
1383 action = REMOVE_SAMPLE;
1384 if (argc != optind+2) {
1385 pa_log(_("You have to specify a sample name to remove"));
1386 goto quit;
1389 sample_name = pa_xstrdup(argv[optind+1]);
1391 } else if (pa_streq(argv[optind], "move-sink-input")) {
1392 action = MOVE_SINK_INPUT;
1393 if (argc != optind+3) {
1394 pa_log(_("You have to specify a sink input index and a sink"));
1395 goto quit;
1398 sink_input_idx = (uint32_t) atoi(argv[optind+1]);
1399 sink_name = pa_xstrdup(argv[optind+2]);
1401 } else if (pa_streq(argv[optind], "move-source-output")) {
1402 action = MOVE_SOURCE_OUTPUT;
1403 if (argc != optind+3) {
1404 pa_log(_("You have to specify a source output index and a source"));
1405 goto quit;
1408 source_output_idx = (uint32_t) atoi(argv[optind+1]);
1409 source_name = pa_xstrdup(argv[optind+2]);
1411 } else if (pa_streq(argv[optind], "load-module")) {
1412 int i;
1413 size_t n = 0;
1414 char *p;
1416 action = LOAD_MODULE;
1418 if (argc <= optind+1) {
1419 pa_log(_("You have to specify a module name and arguments."));
1420 goto quit;
1423 module_name = argv[optind+1];
1425 for (i = optind+2; i < argc; i++)
1426 n += strlen(argv[i])+1;
1428 if (n > 0) {
1429 p = module_args = pa_xmalloc(n);
1431 for (i = optind+2; i < argc; i++)
1432 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
1435 } else if (pa_streq(argv[optind], "unload-module")) {
1436 action = UNLOAD_MODULE;
1438 if (argc != optind+2) {
1439 pa_log(_("You have to specify a module index"));
1440 goto quit;
1443 module_index = (uint32_t) atoi(argv[optind+1]);
1445 } else if (pa_streq(argv[optind], "suspend-sink")) {
1446 action = SUSPEND_SINK;
1448 if (argc > optind+3 || optind+1 >= argc) {
1449 pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
1450 goto quit;
1453 suspend = pa_parse_boolean(argv[argc-1]);
1455 if (argc > optind+2)
1456 sink_name = pa_xstrdup(argv[optind+1]);
1458 } else if (pa_streq(argv[optind], "suspend-source")) {
1459 action = SUSPEND_SOURCE;
1461 if (argc > optind+3 || optind+1 >= argc) {
1462 pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
1463 goto quit;
1466 suspend = pa_parse_boolean(argv[argc-1]);
1468 if (argc > optind+2)
1469 source_name = pa_xstrdup(argv[optind+1]);
1470 } else if (pa_streq(argv[optind], "set-card-profile")) {
1471 action = SET_CARD_PROFILE;
1473 if (argc != optind+3) {
1474 pa_log(_("You have to specify a card name/index and a profile name"));
1475 goto quit;
1478 card_name = pa_xstrdup(argv[optind+1]);
1479 profile_name = pa_xstrdup(argv[optind+2]);
1481 } else if (pa_streq(argv[optind], "set-sink-port")) {
1482 action = SET_SINK_PORT;
1484 if (argc != optind+3) {
1485 pa_log(_("You have to specify a sink name/index and a port name"));
1486 goto quit;
1489 sink_name = pa_xstrdup(argv[optind+1]);
1490 port_name = pa_xstrdup(argv[optind+2]);
1492 } else if (pa_streq(argv[optind], "set-source-port")) {
1493 action = SET_SOURCE_PORT;
1495 if (argc != optind+3) {
1496 pa_log(_("You have to specify a source name/index and a port name"));
1497 goto quit;
1500 source_name = pa_xstrdup(argv[optind+1]);
1501 port_name = pa_xstrdup(argv[optind+2]);
1503 } else if (pa_streq(argv[optind], "set-sink-volume")) {
1504 action = SET_SINK_VOLUME;
1506 if (argc != optind+3) {
1507 pa_log(_("You have to specify a sink name/index and a volume"));
1508 goto quit;
1511 sink_name = pa_xstrdup(argv[optind+1]);
1513 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1514 goto quit;
1516 } else if (pa_streq(argv[optind], "set-source-volume")) {
1517 action = SET_SOURCE_VOLUME;
1519 if (argc != optind+3) {
1520 pa_log(_("You have to specify a source name/index and a volume"));
1521 goto quit;
1524 source_name = pa_xstrdup(argv[optind+1]);
1526 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1527 goto quit;
1529 } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
1530 action = SET_SINK_INPUT_VOLUME;
1532 if (argc != optind+3) {
1533 pa_log(_("You have to specify a sink input index and a volume"));
1534 goto quit;
1537 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1538 pa_log(_("Invalid sink input index"));
1539 goto quit;
1542 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1543 goto quit;
1545 } else if (pa_streq(argv[optind], "set-sink-mute")) {
1546 int b;
1547 action = SET_SINK_MUTE;
1549 if (argc != optind+3) {
1550 pa_log(_("You have to specify a sink name/index and a mute boolean"));
1551 goto quit;
1554 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1555 pa_log(_("Invalid mute specification"));
1556 goto quit;
1559 sink_name = pa_xstrdup(argv[optind+1]);
1560 mute = b;
1562 } else if (pa_streq(argv[optind], "set-source-mute")) {
1563 int b;
1564 action = SET_SOURCE_MUTE;
1566 if (argc != optind+3) {
1567 pa_log(_("You have to specify a source name/index and a mute boolean"));
1568 goto quit;
1571 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1572 pa_log(_("Invalid mute specification"));
1573 goto quit;
1576 source_name = pa_xstrdup(argv[optind+1]);
1577 mute = b;
1579 } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
1580 int b;
1581 action = SET_SINK_INPUT_MUTE;
1583 if (argc != optind+3) {
1584 pa_log(_("You have to specify a sink input index and a mute boolean"));
1585 goto quit;
1588 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1589 pa_log(_("Invalid sink input index specification"));
1590 goto quit;
1593 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1594 pa_log(_("Invalid mute specification"));
1595 goto quit;
1598 mute = b;
1600 } else if (pa_streq(argv[optind], "subscribe"))
1602 action = SUBSCRIBE;
1604 else if (pa_streq(argv[optind], "help")) {
1605 help(bn);
1606 ret = 0;
1607 goto quit;
1611 if (action == NONE) {
1612 pa_log(_("No valid command specified."));
1613 goto quit;
1616 if (!(m = pa_mainloop_new())) {
1617 pa_log(_("pa_mainloop_new() failed."));
1618 goto quit;
1621 mainloop_api = pa_mainloop_get_api(m);
1623 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1624 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1625 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1626 pa_disable_sigpipe();
1628 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1629 pa_log(_("pa_context_new() failed."));
1630 goto quit;
1633 pa_context_set_state_callback(context, context_state_callback, NULL);
1634 if (pa_context_connect(context, server, 0, NULL) < 0) {
1635 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1636 goto quit;
1639 if (pa_mainloop_run(m, &ret) < 0) {
1640 pa_log(_("pa_mainloop_run() failed."));
1641 goto quit;
1644 quit:
1645 if (sample_stream)
1646 pa_stream_unref(sample_stream);
1648 if (context)
1649 pa_context_unref(context);
1651 if (m) {
1652 pa_signal_done();
1653 pa_mainloop_free(m);
1656 pa_xfree(server);
1657 pa_xfree(list_type);
1658 pa_xfree(sample_name);
1659 pa_xfree(sink_name);
1660 pa_xfree(source_name);
1661 pa_xfree(module_args);
1662 pa_xfree(card_name);
1663 pa_xfree(profile_name);
1664 pa_xfree(port_name);
1666 if (sndfile)
1667 sf_close(sndfile);
1669 if (proplist)
1670 pa_proplist_free(proplist);
1672 return ret;