pactl: Separate stat and info actions
[pulseaudio-raopUDP/pulseaudio-raop-alac.git] / src / utils / pactl.c
blobcfa96fe5727bc7ba9b2e54cd86a106fca87d714a
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 uint32_t module_index;
66 static pa_bool_t suspend;
67 static pa_bool_t mute;
68 static pa_volume_t volume;
69 static enum volume_flags {
70 VOL_UINT = 0,
71 VOL_PERCENT = 1,
72 VOL_LINEAR = 2,
73 VOL_DECIBEL = 3,
74 VOL_ABSOLUTE = 0 << 4,
75 VOL_RELATIVE = 1 << 4,
76 } volume_flags;
78 static pa_proplist *proplist = NULL;
80 static SNDFILE *sndfile = NULL;
81 static pa_stream *sample_stream = NULL;
82 static pa_sample_spec sample_spec;
83 static pa_channel_map channel_map;
84 static size_t sample_length = 0;
85 static int actions = 1;
87 static pa_bool_t nl = FALSE;
89 static enum {
90 NONE,
91 EXIT,
92 STAT,
93 INFO,
94 UPLOAD_SAMPLE,
95 PLAY_SAMPLE,
96 REMOVE_SAMPLE,
97 LIST,
98 MOVE_SINK_INPUT,
99 MOVE_SOURCE_OUTPUT,
100 LOAD_MODULE,
101 UNLOAD_MODULE,
102 SUSPEND_SINK,
103 SUSPEND_SOURCE,
104 SET_CARD_PROFILE,
105 SET_SINK_PORT,
106 SET_SOURCE_PORT,
107 SET_SINK_VOLUME,
108 SET_SOURCE_VOLUME,
109 SET_SINK_INPUT_VOLUME,
110 SET_SINK_MUTE,
111 SET_SOURCE_MUTE,
112 SET_SINK_INPUT_MUTE,
113 SUBSCRIBE
114 } action = NONE;
116 static void quit(int ret) {
117 pa_assert(mainloop_api);
118 mainloop_api->quit(mainloop_api, ret);
121 static void context_drain_complete(pa_context *c, void *userdata) {
122 pa_context_disconnect(c);
125 static void drain(void) {
126 pa_operation *o;
128 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
129 pa_context_disconnect(context);
130 else
131 pa_operation_unref(o);
134 static void complete_action(void) {
135 pa_assert(actions > 0);
137 if (!(--actions))
138 drain();
141 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
142 char s[PA_BYTES_SNPRINT_MAX];
143 if (!i) {
144 pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c)));
145 quit(1);
146 return;
149 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
150 printf(_("Currently in use: %u blocks containing %s bytes total.\n"), i->memblock_total, s);
152 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
153 printf(_("Allocated during whole lifetime: %u blocks containing %s bytes total.\n"), i->memblock_allocated, s);
155 pa_bytes_snprint(s, sizeof(s), i->scache_size);
156 printf(_("Sample cache size: %s\n"), s);
158 complete_action();
161 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
162 char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
164 if (!i) {
165 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
166 quit(1);
167 return;
170 printf(_("Server String: %s\n"
171 "Library Protocol Version: %u\n"
172 "Server Protocol Version: %u\n"
173 "Is Local: %s\n"
174 "Client Index: %u\n"
175 "Tile Size: %zu\n"),
176 pa_context_get_server(c),
177 pa_context_get_protocol_version(c),
178 pa_context_get_server_protocol_version(c),
179 pa_yes_no(pa_context_is_local(c)),
180 pa_context_get_index(c),
181 pa_context_get_tile_size(c, NULL));
183 pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
184 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
186 printf(_("User Name: %s\n"
187 "Host Name: %s\n"
188 "Server Name: %s\n"
189 "Server Version: %s\n"
190 "Default Sample Specification: %s\n"
191 "Default Channel Map: %s\n"
192 "Default Sink: %s\n"
193 "Default Source: %s\n"
194 "Cookie: %04x:%04x\n"),
195 i->user_name,
196 i->host_name,
197 i->server_name,
198 i->server_version,
201 i->default_sink_name,
202 i->default_source_name,
203 i->cookie >> 16,
204 i->cookie & 0xFFFFU);
206 complete_action();
209 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
211 static const char *state_table[] = {
212 [1+PA_SINK_INVALID_STATE] = "n/a",
213 [1+PA_SINK_RUNNING] = "RUNNING",
214 [1+PA_SINK_IDLE] = "IDLE",
215 [1+PA_SINK_SUSPENDED] = "SUSPENDED"
218 char
219 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
220 cv[PA_CVOLUME_SNPRINT_MAX],
221 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
222 v[PA_VOLUME_SNPRINT_MAX],
223 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
224 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
225 char *pl;
227 if (is_last < 0) {
228 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
229 quit(1);
230 return;
233 if (is_last) {
234 complete_action();
235 return;
238 pa_assert(i);
240 if (nl)
241 printf("\n");
242 nl = TRUE;
244 printf(_("Sink #%u\n"
245 "\tState: %s\n"
246 "\tName: %s\n"
247 "\tDescription: %s\n"
248 "\tDriver: %s\n"
249 "\tSample Specification: %s\n"
250 "\tChannel Map: %s\n"
251 "\tOwner Module: %u\n"
252 "\tMute: %s\n"
253 "\tVolume: %s%s%s\n"
254 "\t balance %0.2f\n"
255 "\tBase Volume: %s%s%s\n"
256 "\tMonitor Source: %s\n"
257 "\tLatency: %0.0f usec, configured %0.0f usec\n"
258 "\tFlags: %s%s%s%s%s%s\n"
259 "\tProperties:\n\t\t%s\n"),
260 i->index,
261 state_table[1+i->state],
262 i->name,
263 pa_strnull(i->description),
264 pa_strnull(i->driver),
265 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
266 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
267 i->owner_module,
268 pa_yes_no(i->mute),
269 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
270 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
271 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
272 pa_cvolume_get_balance(&i->volume, &i->channel_map),
273 pa_volume_snprint(v, sizeof(v), i->base_volume),
274 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
275 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
276 pa_strnull(i->monitor_source_name),
277 (double) i->latency, (double) i->configured_latency,
278 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
279 i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
280 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
281 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
282 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
283 i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
284 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
286 pa_xfree(pl);
288 if (i->ports) {
289 pa_sink_port_info **p;
291 printf(_("\tPorts:\n"));
292 for (p = i->ports; *p; p++)
293 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
296 if (i->active_port)
297 printf(_("\tActive Port: %s\n"),
298 i->active_port->name);
301 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
303 static const char *state_table[] = {
304 [1+PA_SOURCE_INVALID_STATE] = "n/a",
305 [1+PA_SOURCE_RUNNING] = "RUNNING",
306 [1+PA_SOURCE_IDLE] = "IDLE",
307 [1+PA_SOURCE_SUSPENDED] = "SUSPENDED"
310 char
311 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
312 cv[PA_CVOLUME_SNPRINT_MAX],
313 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
314 v[PA_VOLUME_SNPRINT_MAX],
315 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
316 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
317 char *pl;
319 if (is_last < 0) {
320 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
321 quit(1);
322 return;
325 if (is_last) {
326 complete_action();
327 return;
330 pa_assert(i);
332 if (nl)
333 printf("\n");
334 nl = TRUE;
336 printf(_("Source #%u\n"
337 "\tState: %s\n"
338 "\tName: %s\n"
339 "\tDescription: %s\n"
340 "\tDriver: %s\n"
341 "\tSample Specification: %s\n"
342 "\tChannel Map: %s\n"
343 "\tOwner Module: %u\n"
344 "\tMute: %s\n"
345 "\tVolume: %s%s%s\n"
346 "\t balance %0.2f\n"
347 "\tBase Volume: %s%s%s\n"
348 "\tMonitor of Sink: %s\n"
349 "\tLatency: %0.0f usec, configured %0.0f usec\n"
350 "\tFlags: %s%s%s%s%s%s\n"
351 "\tProperties:\n\t\t%s\n"),
352 i->index,
353 state_table[1+i->state],
354 i->name,
355 pa_strnull(i->description),
356 pa_strnull(i->driver),
357 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
358 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
359 i->owner_module,
360 pa_yes_no(i->mute),
361 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
362 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
363 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
364 pa_cvolume_get_balance(&i->volume, &i->channel_map),
365 pa_volume_snprint(v, sizeof(v), i->base_volume),
366 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
367 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
368 i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
369 (double) i->latency, (double) i->configured_latency,
370 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
371 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
372 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
373 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
374 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
375 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
376 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
378 pa_xfree(pl);
380 if (i->ports) {
381 pa_source_port_info **p;
383 printf(_("\tPorts:\n"));
384 for (p = i->ports; *p; p++)
385 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
388 if (i->active_port)
389 printf(_("\tActive Port: %s\n"),
390 i->active_port->name);
393 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
394 char t[32];
395 char *pl;
397 if (is_last < 0) {
398 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
399 quit(1);
400 return;
403 if (is_last) {
404 complete_action();
405 return;
408 pa_assert(i);
410 if (nl)
411 printf("\n");
412 nl = TRUE;
414 pa_snprintf(t, sizeof(t), "%u", i->n_used);
416 printf(_("Module #%u\n"
417 "\tName: %s\n"
418 "\tArgument: %s\n"
419 "\tUsage counter: %s\n"
420 "\tProperties:\n\t\t%s\n"),
421 i->index,
422 i->name,
423 i->argument ? i->argument : "",
424 i->n_used != PA_INVALID_INDEX ? t : _("n/a"),
425 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
427 pa_xfree(pl);
430 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
431 char t[32];
432 char *pl;
434 if (is_last < 0) {
435 pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
436 quit(1);
437 return;
440 if (is_last) {
441 complete_action();
442 return;
445 pa_assert(i);
447 if (nl)
448 printf("\n");
449 nl = TRUE;
451 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
453 printf(_("Client #%u\n"
454 "\tDriver: %s\n"
455 "\tOwner Module: %s\n"
456 "\tProperties:\n\t\t%s\n"),
457 i->index,
458 pa_strnull(i->driver),
459 i->owner_module != 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_card_info_callback(pa_context *c, const pa_card_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 card information: %s"), pa_strerror(pa_context_errno(c)));
471 complete_action();
472 return;
475 if (is_last) {
476 complete_action();
477 return;
480 pa_assert(i);
482 if (nl)
483 printf("\n");
484 nl = TRUE;
486 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
488 printf(_("Card #%u\n"
489 "\tName: %s\n"
490 "\tDriver: %s\n"
491 "\tOwner Module: %s\n"
492 "\tProperties:\n\t\t%s\n"),
493 i->index,
494 i->name,
495 pa_strnull(i->driver),
496 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
497 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
499 if (i->profiles) {
500 pa_card_profile_info *p;
502 printf(_("\tProfiles:\n"));
503 for (p = i->profiles; p->name; p++)
504 printf("\t\t%s: %s (sinks: %u, sources: %u, priority. %u)\n", p->name, p->description, p->n_sinks, p->n_sources, p->priority);
507 if (i->active_profile)
508 printf(_("\tActive Profile: %s\n"),
509 i->active_profile->name);
511 pa_xfree(pl);
514 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
515 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];
516 char *pl;
518 if (is_last < 0) {
519 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
520 quit(1);
521 return;
524 if (is_last) {
525 complete_action();
526 return;
529 pa_assert(i);
531 if (nl)
532 printf("\n");
533 nl = TRUE;
535 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
536 pa_snprintf(k, sizeof(k), "%u", i->client);
538 printf(_("Sink Input #%u\n"
539 "\tDriver: %s\n"
540 "\tOwner Module: %s\n"
541 "\tClient: %s\n"
542 "\tSink: %u\n"
543 "\tSample Specification: %s\n"
544 "\tChannel Map: %s\n"
545 "\tMute: %s\n"
546 "\tVolume: %s\n"
547 "\t %s\n"
548 "\t balance %0.2f\n"
549 "\tBuffer Latency: %0.0f usec\n"
550 "\tSink Latency: %0.0f usec\n"
551 "\tResample method: %s\n"
552 "\tProperties:\n\t\t%s\n"),
553 i->index,
554 pa_strnull(i->driver),
555 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
556 i->client != PA_INVALID_INDEX ? k : _("n/a"),
557 i->sink,
558 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
559 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
560 pa_yes_no(i->mute),
561 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
562 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
563 pa_cvolume_get_balance(&i->volume, &i->channel_map),
564 (double) i->buffer_usec,
565 (double) i->sink_usec,
566 i->resample_method ? i->resample_method : _("n/a"),
567 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
569 pa_xfree(pl);
572 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
573 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
574 char *pl;
576 if (is_last < 0) {
577 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
578 quit(1);
579 return;
582 if (is_last) {
583 complete_action();
584 return;
587 pa_assert(i);
589 if (nl)
590 printf("\n");
591 nl = TRUE;
594 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
595 pa_snprintf(k, sizeof(k), "%u", i->client);
597 printf(_("Source Output #%u\n"
598 "\tDriver: %s\n"
599 "\tOwner Module: %s\n"
600 "\tClient: %s\n"
601 "\tSource: %u\n"
602 "\tSample Specification: %s\n"
603 "\tChannel Map: %s\n"
604 "\tBuffer Latency: %0.0f usec\n"
605 "\tSource Latency: %0.0f usec\n"
606 "\tResample method: %s\n"
607 "\tProperties:\n\t\t%s\n"),
608 i->index,
609 pa_strnull(i->driver),
610 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
611 i->client != PA_INVALID_INDEX ? k : _("n/a"),
612 i->source,
613 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
614 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
615 (double) i->buffer_usec,
616 (double) i->source_usec,
617 i->resample_method ? i->resample_method : _("n/a"),
618 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
620 pa_xfree(pl);
623 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
624 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];
625 char *pl;
627 if (is_last < 0) {
628 pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
629 quit(1);
630 return;
633 if (is_last) {
634 complete_action();
635 return;
638 pa_assert(i);
640 if (nl)
641 printf("\n");
642 nl = TRUE;
644 pa_bytes_snprint(t, sizeof(t), i->bytes);
646 printf(_("Sample #%u\n"
647 "\tName: %s\n"
648 "\tSample Specification: %s\n"
649 "\tChannel Map: %s\n"
650 "\tVolume: %s\n"
651 "\t %s\n"
652 "\t balance %0.2f\n"
653 "\tDuration: %0.1fs\n"
654 "\tSize: %s\n"
655 "\tLazy: %s\n"
656 "\tFilename: %s\n"
657 "\tProperties:\n\t\t%s\n"),
658 i->index,
659 i->name,
660 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
661 pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
662 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
663 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
664 pa_cvolume_get_balance(&i->volume, &i->channel_map),
665 (double) i->duration/1000000.0,
667 pa_yes_no(i->lazy),
668 i->filename ? i->filename : _("n/a"),
669 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
671 pa_xfree(pl);
674 static void simple_callback(pa_context *c, int success, void *userdata) {
675 if (!success) {
676 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
677 quit(1);
678 return;
681 complete_action();
684 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
685 if (idx == PA_INVALID_INDEX) {
686 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
687 quit(1);
688 return;
691 printf("%u\n", idx);
693 complete_action();
696 static void volume_relative_adjust(pa_cvolume *cv) {
697 pa_assert((volume_flags & VOL_RELATIVE) == VOL_RELATIVE);
699 /* Relative volume change is additive in case of UINT or PERCENT
700 * and multiplicative for LINEAR or DECIBEL */
701 if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
702 pa_volume_t v = pa_cvolume_avg(cv);
703 v = v + volume < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + volume - PA_VOLUME_NORM;
704 pa_cvolume_set(cv, 1, v);
706 if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) {
707 pa_sw_cvolume_multiply_scalar(cv, cv, volume);
711 static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
712 pa_cvolume cv;
714 if (is_last < 0) {
715 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
716 quit(1);
717 return;
720 if (is_last)
721 return;
723 pa_assert(i);
725 cv = i->volume;
726 volume_relative_adjust(&cv);
727 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
730 static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
731 pa_cvolume cv;
733 if (is_last < 0) {
734 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
735 quit(1);
736 return;
739 if (is_last)
740 return;
742 pa_assert(i);
744 cv = i->volume;
745 volume_relative_adjust(&cv);
746 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
749 static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
750 pa_cvolume cv;
752 if (is_last < 0) {
753 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
754 quit(1);
755 return;
758 if (is_last)
759 return;
761 pa_assert(i);
763 cv = i->volume;
764 volume_relative_adjust(&cv);
765 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
768 static void stream_state_callback(pa_stream *s, void *userdata) {
769 pa_assert(s);
771 switch (pa_stream_get_state(s)) {
772 case PA_STREAM_CREATING:
773 case PA_STREAM_READY:
774 break;
776 case PA_STREAM_TERMINATED:
777 drain();
778 break;
780 case PA_STREAM_FAILED:
781 default:
782 pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
783 quit(1);
787 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
788 sf_count_t l;
789 float *d;
790 pa_assert(s && length && sndfile);
792 d = pa_xmalloc(length);
794 pa_assert(sample_length >= length);
795 l = (sf_count_t) (length/pa_frame_size(&sample_spec));
797 if ((sf_readf_float(sndfile, d, l)) != l) {
798 pa_xfree(d);
799 pa_log(_("Premature end of file"));
800 quit(1);
801 return;
804 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
806 sample_length -= length;
808 if (sample_length <= 0) {
809 pa_stream_set_write_callback(sample_stream, NULL, NULL);
810 pa_stream_finish_upload(sample_stream);
814 static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) {
816 switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
818 case PA_SUBSCRIPTION_EVENT_NEW:
819 return _("new");
821 case PA_SUBSCRIPTION_EVENT_CHANGE:
822 return _("change");
824 case PA_SUBSCRIPTION_EVENT_REMOVE:
825 return _("remove");
828 return _("unknown");
831 static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) {
833 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
835 case PA_SUBSCRIPTION_EVENT_SINK:
836 return _("sink");
838 case PA_SUBSCRIPTION_EVENT_SOURCE:
839 return _("source");
841 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
842 return _("sink-input");
844 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
845 return _("source-output");
847 case PA_SUBSCRIPTION_EVENT_MODULE:
848 return _("module");
850 case PA_SUBSCRIPTION_EVENT_CLIENT:
851 return _("client");
853 case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
854 return _("sample-cache");
856 case PA_SUBSCRIPTION_EVENT_SERVER:
857 return _("server");
859 case PA_SUBSCRIPTION_EVENT_CARD:
860 return _("server");
863 return _("unknown");
866 static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
867 pa_assert(c);
869 printf(_("Event '%s' on %s #%u\n"),
870 subscription_event_type_to_string(t),
871 subscription_event_facility_to_string(t),
872 idx);
875 static void context_state_callback(pa_context *c, void *userdata) {
876 pa_assert(c);
877 switch (pa_context_get_state(c)) {
878 case PA_CONTEXT_CONNECTING:
879 case PA_CONTEXT_AUTHORIZING:
880 case PA_CONTEXT_SETTING_NAME:
881 break;
883 case PA_CONTEXT_READY:
884 switch (action) {
885 case STAT:
886 pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
887 break;
889 case INFO:
890 pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
891 break;
893 case PLAY_SAMPLE:
894 pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL));
895 break;
897 case REMOVE_SAMPLE:
898 pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
899 break;
901 case UPLOAD_SAMPLE:
902 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
903 pa_assert(sample_stream);
905 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
906 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
907 pa_stream_connect_upload(sample_stream, sample_length);
908 break;
910 case EXIT:
911 pa_operation_unref(pa_context_exit_daemon(c, simple_callback, NULL));
912 break;
914 case LIST:
915 if (list_type) {
916 if (pa_streq(list_type, "modules"))
917 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
918 else if (pa_streq(list_type, "sinks"))
919 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
920 else if (pa_streq(list_type, "sources"))
921 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
922 else if (pa_streq(list_type, "sink-inputs"))
923 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
924 else if (pa_streq(list_type, "source-outputs"))
925 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
926 else if (pa_streq(list_type, "clients"))
927 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
928 else if (pa_streq(list_type, "samples"))
929 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
930 else if (pa_streq(list_type, "cards"))
931 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
932 else
933 pa_assert_not_reached();
934 } else {
935 actions = 8;
936 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
937 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
938 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
939 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
940 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
941 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
942 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
943 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
945 break;
947 case MOVE_SINK_INPUT:
948 pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL));
949 break;
951 case MOVE_SOURCE_OUTPUT:
952 pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
953 break;
955 case LOAD_MODULE:
956 pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
957 break;
959 case UNLOAD_MODULE:
960 pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
961 break;
963 case SUSPEND_SINK:
964 if (sink_name)
965 pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
966 else
967 pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
968 break;
970 case SUSPEND_SOURCE:
971 if (source_name)
972 pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
973 else
974 pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
975 break;
977 case SET_CARD_PROFILE:
978 pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
979 break;
981 case SET_SINK_PORT:
982 pa_operation_unref(pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL));
983 break;
985 case SET_SOURCE_PORT:
986 pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL));
987 break;
989 case SET_SINK_MUTE:
990 pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL));
991 break;
993 case SET_SOURCE_MUTE:
994 pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL));
995 break;
997 case SET_SINK_INPUT_MUTE:
998 pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
999 break;
1001 case SET_SINK_VOLUME:
1002 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1003 pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
1004 } else {
1005 pa_cvolume v;
1006 pa_cvolume_set(&v, 1, volume);
1007 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
1009 break;
1011 case SET_SOURCE_VOLUME:
1012 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1013 pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
1014 } else {
1015 pa_cvolume v;
1016 pa_cvolume_set(&v, 1, volume);
1017 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
1019 break;
1021 case SET_SINK_INPUT_VOLUME:
1022 if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1023 pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
1024 } else {
1025 pa_cvolume v;
1026 pa_cvolume_set(&v, 1, volume);
1027 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
1029 break;
1031 case SUBSCRIBE:
1032 pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
1034 pa_operation_unref(pa_context_subscribe(
1036 PA_SUBSCRIPTION_MASK_SINK|
1037 PA_SUBSCRIPTION_MASK_SOURCE|
1038 PA_SUBSCRIPTION_MASK_SINK_INPUT|
1039 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
1040 PA_SUBSCRIPTION_MASK_MODULE|
1041 PA_SUBSCRIPTION_MASK_CLIENT|
1042 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
1043 PA_SUBSCRIPTION_MASK_SERVER|
1044 PA_SUBSCRIPTION_MASK_CARD,
1045 NULL,
1046 NULL));
1047 break;
1049 default:
1050 pa_assert_not_reached();
1052 break;
1054 case PA_CONTEXT_TERMINATED:
1055 quit(0);
1056 break;
1058 case PA_CONTEXT_FAILED:
1059 default:
1060 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
1061 quit(1);
1065 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
1066 pa_log(_("Got SIGINT, exiting."));
1067 quit(0);
1070 static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) {
1071 double v;
1072 char *vs;
1074 pa_assert(vol_spec);
1075 pa_assert(vol);
1076 pa_assert(vol_flags);
1078 vs = pa_xstrdup(vol_spec);
1080 *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;
1081 if (strchr(vs, '.'))
1082 *vol_flags |= VOL_LINEAR;
1083 if (pa_endswith(vs, "%")) {
1084 *vol_flags |= VOL_PERCENT;
1085 vs[strlen(vs)-1] = 0;
1087 if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) {
1088 *vol_flags |= VOL_DECIBEL;
1089 vs[strlen(vs)-2] = 0;
1092 if (pa_atod(vs, &v) < 0) {
1093 pa_log(_("Invalid volume specification"));
1094 pa_xfree(vs);
1095 return -1;
1098 pa_xfree(vs);
1100 if ((*vol_flags & VOL_RELATIVE) == VOL_RELATIVE) {
1101 if ((*vol_flags & 0x0F) == VOL_UINT)
1102 v += (double) PA_VOLUME_NORM;
1103 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1104 v += 100.0;
1105 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1106 v += 1.0;
1108 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1109 v = v * (double) PA_VOLUME_NORM / 100;
1110 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1111 v = pa_sw_volume_from_linear(v);
1112 if ((*vol_flags & 0x0F) == VOL_DECIBEL)
1113 v = pa_sw_volume_from_dB(v);
1115 if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) {
1116 pa_log(_("Volume outside permissible range.\n"));
1117 return -1;
1120 *vol = (pa_volume_t) v;
1122 return 0;
1125 static void help(const char *argv0) {
1127 printf(_("%s [options] stat\n"
1128 "%s [options] info\n"
1129 "%s [options] list [TYPE]\n"
1130 "%s [options] exit\n"
1131 "%s [options] upload-sample FILENAME [NAME]\n"
1132 "%s [options] play-sample NAME [SINK]\n"
1133 "%s [options] remove-sample NAME\n"
1134 "%s [options] move-sink-input SINKINPUT SINK\n"
1135 "%s [options] move-source-output SOURCEOUTPUT SOURCE\n"
1136 "%s [options] load-module NAME [ARGS ...]\n"
1137 "%s [options] unload-module MODULE\n"
1138 "%s [options] suspend-sink SINK 1|0\n"
1139 "%s [options] suspend-source SOURCE 1|0\n"
1140 "%s [options] set-card-profile CARD PROFILE\n"
1141 "%s [options] set-sink-port SINK PORT\n"
1142 "%s [options] set-source-port SOURCE PORT\n"
1143 "%s [options] set-sink-volume SINK VOLUME\n"
1144 "%s [options] set-source-volume SOURCE VOLUME\n"
1145 "%s [options] set-sink-input-volume SINKINPUT VOLUME\n"
1146 "%s [options] set-sink-mute SINK 1|0\n"
1147 "%s [options] set-source-mute SOURCE 1|0\n"
1148 "%s [options] set-sink-input-mute SINKINPUT 1|0\n"
1149 "%s [options] subscribe\n\n"
1150 " -h, --help Show this help\n"
1151 " --version Show version\n\n"
1152 " -s, --server=SERVER The name of the server to connect to\n"
1153 " -n, --client-name=NAME How to call this client on the server\n"),
1154 argv0, argv0, argv0, argv0, argv0,
1155 argv0, argv0, argv0, argv0, argv0,
1156 argv0, argv0, argv0, argv0, argv0,
1157 argv0, argv0, argv0, argv0, argv0,
1158 argv0, argv0, argv0);
1161 enum {
1162 ARG_VERSION = 256
1165 int main(int argc, char *argv[]) {
1166 pa_mainloop *m = NULL;
1167 int ret = 1, c;
1168 char *server = NULL, *bn;
1170 static const struct option long_options[] = {
1171 {"server", 1, NULL, 's'},
1172 {"client-name", 1, NULL, 'n'},
1173 {"version", 0, NULL, ARG_VERSION},
1174 {"help", 0, NULL, 'h'},
1175 {NULL, 0, NULL, 0}
1178 setlocale(LC_ALL, "");
1179 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
1181 bn = pa_path_get_filename(argv[0]);
1183 proplist = pa_proplist_new();
1185 while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
1186 switch (c) {
1187 case 'h' :
1188 help(bn);
1189 ret = 0;
1190 goto quit;
1192 case ARG_VERSION:
1193 printf(_("pactl %s\n"
1194 "Compiled with libpulse %s\n"
1195 "Linked with libpulse %s\n"),
1196 PACKAGE_VERSION,
1197 pa_get_headers_version(),
1198 pa_get_library_version());
1199 ret = 0;
1200 goto quit;
1202 case 's':
1203 pa_xfree(server);
1204 server = pa_xstrdup(optarg);
1205 break;
1207 case 'n': {
1208 char *t;
1210 if (!(t = pa_locale_to_utf8(optarg)) ||
1211 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
1213 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
1214 pa_xfree(t);
1215 goto quit;
1218 pa_xfree(t);
1219 break;
1222 default:
1223 goto quit;
1227 if (optind < argc) {
1228 if (pa_streq(argv[optind], "stat"))
1229 action = STAT;
1231 else if (pa_streq(argv[optind], "info"))
1232 action = INFO;
1234 else if (pa_streq(argv[optind], "exit"))
1235 action = EXIT;
1237 else if (pa_streq(argv[optind], "list")) {
1238 action = LIST;
1240 for (int i = optind+1; i < argc; i++){
1241 if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
1242 pa_streq(argv[i], "sinks") || pa_streq(argv[i], "sink-inputs") ||
1243 pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
1244 pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
1245 list_type = pa_xstrdup(argv[i]);
1246 } else {
1247 pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
1248 goto quit;
1252 } else if (pa_streq(argv[optind], "upload-sample")) {
1253 struct SF_INFO sfi;
1254 action = UPLOAD_SAMPLE;
1256 if (optind+1 >= argc) {
1257 pa_log(_("Please specify a sample file to load"));
1258 goto quit;
1261 if (optind+2 < argc)
1262 sample_name = pa_xstrdup(argv[optind+2]);
1263 else {
1264 char *f = pa_path_get_filename(argv[optind+1]);
1265 sample_name = pa_xstrndup(f, strcspn(f, "."));
1268 pa_zero(sfi);
1269 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
1270 pa_log(_("Failed to open sound file."));
1271 goto quit;
1274 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1275 pa_log(_("Failed to determine sample specification from file."));
1276 goto quit;
1278 sample_spec.format = PA_SAMPLE_FLOAT32;
1280 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1281 if (sample_spec.channels > 2)
1282 pa_log(_("Warning: Failed to determine sample specification from file."));
1283 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1286 pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
1287 sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
1289 } else if (pa_streq(argv[optind], "play-sample")) {
1290 action = PLAY_SAMPLE;
1291 if (argc != optind+2 && argc != optind+3) {
1292 pa_log(_("You have to specify a sample name to play"));
1293 goto quit;
1296 sample_name = pa_xstrdup(argv[optind+1]);
1298 if (optind+2 < argc)
1299 sink_name = pa_xstrdup(argv[optind+2]);
1301 } else if (pa_streq(argv[optind], "remove-sample")) {
1302 action = REMOVE_SAMPLE;
1303 if (argc != optind+2) {
1304 pa_log(_("You have to specify a sample name to remove"));
1305 goto quit;
1308 sample_name = pa_xstrdup(argv[optind+1]);
1310 } else if (pa_streq(argv[optind], "move-sink-input")) {
1311 action = MOVE_SINK_INPUT;
1312 if (argc != optind+3) {
1313 pa_log(_("You have to specify a sink input index and a sink"));
1314 goto quit;
1317 sink_input_idx = (uint32_t) atoi(argv[optind+1]);
1318 sink_name = pa_xstrdup(argv[optind+2]);
1320 } else if (pa_streq(argv[optind], "move-source-output")) {
1321 action = MOVE_SOURCE_OUTPUT;
1322 if (argc != optind+3) {
1323 pa_log(_("You have to specify a source output index and a source"));
1324 goto quit;
1327 source_output_idx = (uint32_t) atoi(argv[optind+1]);
1328 source_name = pa_xstrdup(argv[optind+2]);
1330 } else if (pa_streq(argv[optind], "load-module")) {
1331 int i;
1332 size_t n = 0;
1333 char *p;
1335 action = LOAD_MODULE;
1337 if (argc <= optind+1) {
1338 pa_log(_("You have to specify a module name and arguments."));
1339 goto quit;
1342 module_name = argv[optind+1];
1344 for (i = optind+2; i < argc; i++)
1345 n += strlen(argv[i])+1;
1347 if (n > 0) {
1348 p = module_args = pa_xmalloc(n);
1350 for (i = optind+2; i < argc; i++)
1351 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
1354 } else if (pa_streq(argv[optind], "unload-module")) {
1355 action = UNLOAD_MODULE;
1357 if (argc != optind+2) {
1358 pa_log(_("You have to specify a module index"));
1359 goto quit;
1362 module_index = (uint32_t) atoi(argv[optind+1]);
1364 } else if (pa_streq(argv[optind], "suspend-sink")) {
1365 action = SUSPEND_SINK;
1367 if (argc > optind+3 || optind+1 >= argc) {
1368 pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
1369 goto quit;
1372 suspend = pa_parse_boolean(argv[argc-1]);
1374 if (argc > optind+2)
1375 sink_name = pa_xstrdup(argv[optind+1]);
1377 } else if (pa_streq(argv[optind], "suspend-source")) {
1378 action = SUSPEND_SOURCE;
1380 if (argc > optind+3 || optind+1 >= argc) {
1381 pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
1382 goto quit;
1385 suspend = pa_parse_boolean(argv[argc-1]);
1387 if (argc > optind+2)
1388 source_name = pa_xstrdup(argv[optind+1]);
1389 } else if (pa_streq(argv[optind], "set-card-profile")) {
1390 action = SET_CARD_PROFILE;
1392 if (argc != optind+3) {
1393 pa_log(_("You have to specify a card name/index and a profile name"));
1394 goto quit;
1397 card_name = pa_xstrdup(argv[optind+1]);
1398 profile_name = pa_xstrdup(argv[optind+2]);
1400 } else if (pa_streq(argv[optind], "set-sink-port")) {
1401 action = SET_SINK_PORT;
1403 if (argc != optind+3) {
1404 pa_log(_("You have to specify a sink name/index and a port name"));
1405 goto quit;
1408 sink_name = pa_xstrdup(argv[optind+1]);
1409 port_name = pa_xstrdup(argv[optind+2]);
1411 } else if (pa_streq(argv[optind], "set-source-port")) {
1412 action = SET_SOURCE_PORT;
1414 if (argc != optind+3) {
1415 pa_log(_("You have to specify a source name/index and a port name"));
1416 goto quit;
1419 source_name = pa_xstrdup(argv[optind+1]);
1420 port_name = pa_xstrdup(argv[optind+2]);
1422 } else if (pa_streq(argv[optind], "set-sink-volume")) {
1423 action = SET_SINK_VOLUME;
1425 if (argc != optind+3) {
1426 pa_log(_("You have to specify a sink name/index and a volume"));
1427 goto quit;
1430 sink_name = pa_xstrdup(argv[optind+1]);
1432 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1433 goto quit;
1435 } else if (pa_streq(argv[optind], "set-source-volume")) {
1436 action = SET_SOURCE_VOLUME;
1438 if (argc != optind+3) {
1439 pa_log(_("You have to specify a source name/index and a volume"));
1440 goto quit;
1443 source_name = pa_xstrdup(argv[optind+1]);
1445 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1446 goto quit;
1448 } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
1449 action = SET_SINK_INPUT_VOLUME;
1451 if (argc != optind+3) {
1452 pa_log(_("You have to specify a sink input index and a volume"));
1453 goto quit;
1456 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1457 pa_log(_("Invalid sink input index"));
1458 goto quit;
1461 if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
1462 goto quit;
1464 } else if (pa_streq(argv[optind], "set-sink-mute")) {
1465 int b;
1466 action = SET_SINK_MUTE;
1468 if (argc != optind+3) {
1469 pa_log(_("You have to specify a sink name/index and a mute boolean"));
1470 goto quit;
1473 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1474 pa_log(_("Invalid mute specification"));
1475 goto quit;
1478 sink_name = pa_xstrdup(argv[optind+1]);
1479 mute = b;
1481 } else if (pa_streq(argv[optind], "set-source-mute")) {
1482 int b;
1483 action = SET_SOURCE_MUTE;
1485 if (argc != optind+3) {
1486 pa_log(_("You have to specify a source name/index and a mute boolean"));
1487 goto quit;
1490 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1491 pa_log(_("Invalid mute specification"));
1492 goto quit;
1495 source_name = pa_xstrdup(argv[optind+1]);
1496 mute = b;
1498 } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
1499 int b;
1500 action = SET_SINK_INPUT_MUTE;
1502 if (argc != optind+3) {
1503 pa_log(_("You have to specify a sink input index and a mute boolean"));
1504 goto quit;
1507 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1508 pa_log(_("Invalid sink input index specification"));
1509 goto quit;
1512 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1513 pa_log(_("Invalid mute specification"));
1514 goto quit;
1517 mute = b;
1519 } else if (pa_streq(argv[optind], "subscribe"))
1521 action = SUBSCRIBE;
1523 else if (pa_streq(argv[optind], "help")) {
1524 help(bn);
1525 ret = 0;
1526 goto quit;
1530 if (action == NONE) {
1531 pa_log(_("No valid command specified."));
1532 goto quit;
1535 if (!(m = pa_mainloop_new())) {
1536 pa_log(_("pa_mainloop_new() failed."));
1537 goto quit;
1540 mainloop_api = pa_mainloop_get_api(m);
1542 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1543 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1544 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1545 pa_disable_sigpipe();
1547 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1548 pa_log(_("pa_context_new() failed."));
1549 goto quit;
1552 pa_context_set_state_callback(context, context_state_callback, NULL);
1553 if (pa_context_connect(context, server, 0, NULL) < 0) {
1554 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1555 goto quit;
1558 if (pa_mainloop_run(m, &ret) < 0) {
1559 pa_log(_("pa_mainloop_run() failed."));
1560 goto quit;
1563 quit:
1564 if (sample_stream)
1565 pa_stream_unref(sample_stream);
1567 if (context)
1568 pa_context_unref(context);
1570 if (m) {
1571 pa_signal_done();
1572 pa_mainloop_free(m);
1575 pa_xfree(server);
1576 pa_xfree(list_type);
1577 pa_xfree(sample_name);
1578 pa_xfree(sink_name);
1579 pa_xfree(source_name);
1580 pa_xfree(module_args);
1581 pa_xfree(card_name);
1582 pa_xfree(profile_name);
1583 pa_xfree(port_name);
1585 if (sndfile)
1586 sf_close(sndfile);
1588 if (proplist)
1589 pa_proplist_free(proplist);
1591 return ret;