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