]> code.delx.au - pulseaudio/blob - src/utils/pactl.c
pactl: implement pactl subscribe
[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 <limits.h>
34 #include <getopt.h>
35 #include <locale.h>
36
37 #include <sndfile.h>
38
39 #include <pulse/i18n.h>
40 #include <pulse/pulseaudio.h>
41
42 #include <pulsecore/macro.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/sndfile-util.h>
46
47 static pa_context *context = NULL;
48 static pa_mainloop_api *mainloop_api = NULL;
49
50 static char
51 *sample_name = NULL,
52 *sink_name = NULL,
53 *source_name = NULL,
54 *module_name = NULL,
55 *module_args = NULL,
56 *card_name = NULL,
57 *profile_name = NULL,
58 *port_name = NULL;
59
60 static uint32_t
61 sink_input_idx = PA_INVALID_INDEX,
62 source_output_idx = PA_INVALID_INDEX;
63
64 static uint32_t module_index;
65 static pa_bool_t suspend;
66 static pa_bool_t mute;
67 static pa_volume_t volume;
68
69 static pa_proplist *proplist = NULL;
70
71 static SNDFILE *sndfile = NULL;
72 static pa_stream *sample_stream = NULL;
73 static pa_sample_spec sample_spec;
74 static pa_channel_map channel_map;
75 static size_t sample_length = 0;
76 static int actions = 1;
77
78 static pa_bool_t nl = FALSE;
79
80 static enum {
81 NONE,
82 EXIT,
83 STAT,
84 UPLOAD_SAMPLE,
85 PLAY_SAMPLE,
86 REMOVE_SAMPLE,
87 LIST,
88 MOVE_SINK_INPUT,
89 MOVE_SOURCE_OUTPUT,
90 LOAD_MODULE,
91 UNLOAD_MODULE,
92 SUSPEND_SINK,
93 SUSPEND_SOURCE,
94 SET_CARD_PROFILE,
95 SET_SINK_PORT,
96 SET_SOURCE_PORT,
97 SET_SINK_VOLUME,
98 SET_SOURCE_VOLUME,
99 SET_SINK_INPUT_VOLUME,
100 SET_SINK_MUTE,
101 SET_SOURCE_MUTE,
102 SET_SINK_INPUT_MUTE,
103 SUBSCRIBE
104 } action = NONE;
105
106 static void quit(int ret) {
107 pa_assert(mainloop_api);
108 mainloop_api->quit(mainloop_api, ret);
109 }
110
111 static void context_drain_complete(pa_context *c, void *userdata) {
112 pa_context_disconnect(c);
113 }
114
115 static void drain(void) {
116 pa_operation *o;
117
118 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
119 pa_context_disconnect(context);
120 else
121 pa_operation_unref(o);
122 }
123
124 static void complete_action(void) {
125 pa_assert(actions > 0);
126
127 if (!(--actions))
128 drain();
129 }
130
131 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
132 char s[PA_BYTES_SNPRINT_MAX];
133 if (!i) {
134 pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c)));
135 quit(1);
136 return;
137 }
138
139 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
140 printf(_("Currently in use: %u blocks containing %s bytes total.\n"), i->memblock_total, s);
141
142 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
143 printf(_("Allocated during whole lifetime: %u blocks containing %s bytes total.\n"), i->memblock_allocated, s);
144
145 pa_bytes_snprint(s, sizeof(s), i->scache_size);
146 printf(_("Sample cache size: %s\n"), s);
147
148 complete_action();
149 }
150
151 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
152 char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
153
154 if (!i) {
155 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
156 quit(1);
157 return;
158 }
159
160 printf(_("Server String: %s\n"
161 "Library Protocol Version: %u\n"
162 "Server Protocol Version: %u\n"
163 "Is Local: %s\n"
164 "Client Index: %u\n"
165 "Tile Size: %zu\n"),
166 pa_context_get_server(c),
167 pa_context_get_protocol_version(c),
168 pa_context_get_server_protocol_version(c),
169 pa_yes_no(pa_context_is_local(c)),
170 pa_context_get_index(c),
171 pa_context_get_tile_size(c, NULL));
172
173 pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
174 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
175
176 printf(_("User Name: %s\n"
177 "Host Name: %s\n"
178 "Server Name: %s\n"
179 "Server Version: %s\n"
180 "Default Sample Specification: %s\n"
181 "Default Channel Map: %s\n"
182 "Default Sink: %s\n"
183 "Default Source: %s\n"
184 "Cookie: %04x:%04x\n"),
185 i->user_name,
186 i->host_name,
187 i->server_name,
188 i->server_version,
189 ss,
190 cm,
191 i->default_sink_name,
192 i->default_source_name,
193 i->cookie >> 16,
194 i->cookie & 0xFFFFU);
195
196 complete_action();
197 }
198
199 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
200
201 static const char *state_table[] = {
202 [1+PA_SINK_INVALID_STATE] = "n/a",
203 [1+PA_SINK_RUNNING] = "RUNNING",
204 [1+PA_SINK_IDLE] = "IDLE",
205 [1+PA_SINK_SUSPENDED] = "SUSPENDED"
206 };
207
208 char
209 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
210 cv[PA_CVOLUME_SNPRINT_MAX],
211 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
212 v[PA_VOLUME_SNPRINT_MAX],
213 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
214 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
215 char *pl;
216
217 if (is_last < 0) {
218 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
219 quit(1);
220 return;
221 }
222
223 if (is_last) {
224 complete_action();
225 return;
226 }
227
228 pa_assert(i);
229
230 if (nl)
231 printf("\n");
232 nl = TRUE;
233
234 printf(_("Sink #%u\n"
235 "\tState: %s\n"
236 "\tName: %s\n"
237 "\tDescription: %s\n"
238 "\tDriver: %s\n"
239 "\tSample Specification: %s\n"
240 "\tChannel Map: %s\n"
241 "\tOwner Module: %u\n"
242 "\tMute: %s\n"
243 "\tVolume: %s%s%s\n"
244 "\t balance %0.2f\n"
245 "\tBase Volume: %s%s%s\n"
246 "\tMonitor Source: %s\n"
247 "\tLatency: %0.0f usec, configured %0.0f usec\n"
248 "\tFlags: %s%s%s%s%s%s\n"
249 "\tProperties:\n\t\t%s\n"),
250 i->index,
251 state_table[1+i->state],
252 i->name,
253 pa_strnull(i->description),
254 pa_strnull(i->driver),
255 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
256 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
257 i->owner_module,
258 pa_yes_no(i->mute),
259 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
260 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
261 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
262 pa_cvolume_get_balance(&i->volume, &i->channel_map),
263 pa_volume_snprint(v, sizeof(v), i->base_volume),
264 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
265 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
266 pa_strnull(i->monitor_source_name),
267 (double) i->latency, (double) i->configured_latency,
268 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
269 i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
270 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
271 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
272 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
273 i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
274 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
275
276 pa_xfree(pl);
277
278 if (i->ports) {
279 pa_sink_port_info **p;
280
281 printf(_("\tPorts:\n"));
282 for (p = i->ports; *p; p++)
283 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
284 }
285
286 if (i->active_port)
287 printf(_("\tActive Port: %s\n"),
288 i->active_port->name);
289 }
290
291 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
292
293 static const char *state_table[] = {
294 [1+PA_SOURCE_INVALID_STATE] = "n/a",
295 [1+PA_SOURCE_RUNNING] = "RUNNING",
296 [1+PA_SOURCE_IDLE] = "IDLE",
297 [1+PA_SOURCE_SUSPENDED] = "SUSPENDED"
298 };
299
300 char
301 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
302 cv[PA_CVOLUME_SNPRINT_MAX],
303 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
304 v[PA_VOLUME_SNPRINT_MAX],
305 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
306 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
307 char *pl;
308
309 if (is_last < 0) {
310 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
311 quit(1);
312 return;
313 }
314
315 if (is_last) {
316 complete_action();
317 return;
318 }
319
320 pa_assert(i);
321
322 if (nl)
323 printf("\n");
324 nl = TRUE;
325
326 printf(_("Source #%u\n"
327 "\tState: %s\n"
328 "\tName: %s\n"
329 "\tDescription: %s\n"
330 "\tDriver: %s\n"
331 "\tSample Specification: %s\n"
332 "\tChannel Map: %s\n"
333 "\tOwner Module: %u\n"
334 "\tMute: %s\n"
335 "\tVolume: %s%s%s\n"
336 "\t balance %0.2f\n"
337 "\tBase Volume: %s%s%s\n"
338 "\tMonitor of Sink: %s\n"
339 "\tLatency: %0.0f usec, configured %0.0f usec\n"
340 "\tFlags: %s%s%s%s%s%s\n"
341 "\tProperties:\n\t\t%s\n"),
342 i->index,
343 state_table[1+i->state],
344 i->name,
345 pa_strnull(i->description),
346 pa_strnull(i->driver),
347 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
348 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
349 i->owner_module,
350 pa_yes_no(i->mute),
351 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
352 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
353 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
354 pa_cvolume_get_balance(&i->volume, &i->channel_map),
355 pa_volume_snprint(v, sizeof(v), i->base_volume),
356 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
357 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
358 i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
359 (double) i->latency, (double) i->configured_latency,
360 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
361 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
362 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
363 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
364 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
365 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
366 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
367
368 pa_xfree(pl);
369
370 if (i->ports) {
371 pa_source_port_info **p;
372
373 printf(_("\tPorts:\n"));
374 for (p = i->ports; *p; p++)
375 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
376 }
377
378 if (i->active_port)
379 printf(_("\tActive Port: %s\n"),
380 i->active_port->name);
381 }
382
383 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
384 char t[32];
385 char *pl;
386
387 if (is_last < 0) {
388 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
389 quit(1);
390 return;
391 }
392
393 if (is_last) {
394 complete_action();
395 return;
396 }
397
398 pa_assert(i);
399
400 if (nl)
401 printf("\n");
402 nl = TRUE;
403
404 pa_snprintf(t, sizeof(t), "%u", i->n_used);
405
406 printf(_("Module #%u\n"
407 "\tName: %s\n"
408 "\tArgument: %s\n"
409 "\tUsage counter: %s\n"
410 "\tProperties:\n\t\t%s\n"),
411 i->index,
412 i->name,
413 i->argument ? i->argument : "",
414 i->n_used != PA_INVALID_INDEX ? t : _("n/a"),
415 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
416
417 pa_xfree(pl);
418 }
419
420 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
421 char t[32];
422 char *pl;
423
424 if (is_last < 0) {
425 pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
426 quit(1);
427 return;
428 }
429
430 if (is_last) {
431 complete_action();
432 return;
433 }
434
435 pa_assert(i);
436
437 if (nl)
438 printf("\n");
439 nl = TRUE;
440
441 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
442
443 printf(_("Client #%u\n"
444 "\tDriver: %s\n"
445 "\tOwner Module: %s\n"
446 "\tProperties:\n\t\t%s\n"),
447 i->index,
448 pa_strnull(i->driver),
449 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
450 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
451
452 pa_xfree(pl);
453 }
454
455 static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_last, void *userdata) {
456 char t[32];
457 char *pl;
458
459 if (is_last < 0) {
460 pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c)));
461 complete_action();
462 return;
463 }
464
465 if (is_last) {
466 complete_action();
467 return;
468 }
469
470 pa_assert(i);
471
472 if (nl)
473 printf("\n");
474 nl = TRUE;
475
476 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
477
478 printf(_("Card #%u\n"
479 "\tName: %s\n"
480 "\tDriver: %s\n"
481 "\tOwner Module: %s\n"
482 "\tProperties:\n\t\t%s\n"),
483 i->index,
484 i->name,
485 pa_strnull(i->driver),
486 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
487 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
488
489 if (i->profiles) {
490 pa_card_profile_info *p;
491
492 printf(_("\tProfiles:\n"));
493 for (p = i->profiles; p->name; p++)
494 printf("\t\t%s: %s (sinks: %u, sources: %u, priority. %u)\n", p->name, p->description, p->n_sinks, p->n_sources, p->priority);
495 }
496
497 if (i->active_profile)
498 printf(_("\tActive Profile: %s\n"),
499 i->active_profile->name);
500
501 pa_xfree(pl);
502 }
503
504 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
505 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];
506 char *pl;
507
508 if (is_last < 0) {
509 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
510 quit(1);
511 return;
512 }
513
514 if (is_last) {
515 complete_action();
516 return;
517 }
518
519 pa_assert(i);
520
521 if (nl)
522 printf("\n");
523 nl = TRUE;
524
525 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
526 pa_snprintf(k, sizeof(k), "%u", i->client);
527
528 printf(_("Sink Input #%u\n"
529 "\tDriver: %s\n"
530 "\tOwner Module: %s\n"
531 "\tClient: %s\n"
532 "\tSink: %u\n"
533 "\tSample Specification: %s\n"
534 "\tChannel Map: %s\n"
535 "\tMute: %s\n"
536 "\tVolume: %s\n"
537 "\t %s\n"
538 "\t balance %0.2f\n"
539 "\tBuffer Latency: %0.0f usec\n"
540 "\tSink Latency: %0.0f usec\n"
541 "\tResample method: %s\n"
542 "\tProperties:\n\t\t%s\n"),
543 i->index,
544 pa_strnull(i->driver),
545 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
546 i->client != PA_INVALID_INDEX ? k : _("n/a"),
547 i->sink,
548 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
549 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
550 pa_yes_no(i->mute),
551 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
552 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
553 pa_cvolume_get_balance(&i->volume, &i->channel_map),
554 (double) i->buffer_usec,
555 (double) i->sink_usec,
556 i->resample_method ? i->resample_method : _("n/a"),
557 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
558
559 pa_xfree(pl);
560 }
561
562 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
563 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
564 char *pl;
565
566 if (is_last < 0) {
567 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
568 quit(1);
569 return;
570 }
571
572 if (is_last) {
573 complete_action();
574 return;
575 }
576
577 pa_assert(i);
578
579 if (nl)
580 printf("\n");
581 nl = TRUE;
582
583
584 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
585 pa_snprintf(k, sizeof(k), "%u", i->client);
586
587 printf(_("Source Output #%u\n"
588 "\tDriver: %s\n"
589 "\tOwner Module: %s\n"
590 "\tClient: %s\n"
591 "\tSource: %u\n"
592 "\tSample Specification: %s\n"
593 "\tChannel Map: %s\n"
594 "\tBuffer Latency: %0.0f usec\n"
595 "\tSource Latency: %0.0f usec\n"
596 "\tResample method: %s\n"
597 "\tProperties:\n\t\t%s\n"),
598 i->index,
599 pa_strnull(i->driver),
600 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
601 i->client != PA_INVALID_INDEX ? k : _("n/a"),
602 i->source,
603 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
604 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
605 (double) i->buffer_usec,
606 (double) i->source_usec,
607 i->resample_method ? i->resample_method : _("n/a"),
608 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
609
610 pa_xfree(pl);
611 }
612
613 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
614 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];
615 char *pl;
616
617 if (is_last < 0) {
618 pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
619 quit(1);
620 return;
621 }
622
623 if (is_last) {
624 complete_action();
625 return;
626 }
627
628 pa_assert(i);
629
630 if (nl)
631 printf("\n");
632 nl = TRUE;
633
634 pa_bytes_snprint(t, sizeof(t), i->bytes);
635
636 printf(_("Sample #%u\n"
637 "\tName: %s\n"
638 "\tSample Specification: %s\n"
639 "\tChannel Map: %s\n"
640 "\tVolume: %s\n"
641 "\t %s\n"
642 "\t balance %0.2f\n"
643 "\tDuration: %0.1fs\n"
644 "\tSize: %s\n"
645 "\tLazy: %s\n"
646 "\tFilename: %s\n"
647 "\tProperties:\n\t\t%s\n"),
648 i->index,
649 i->name,
650 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
651 pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
652 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
653 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
654 pa_cvolume_get_balance(&i->volume, &i->channel_map),
655 (double) i->duration/1000000.0,
656 t,
657 pa_yes_no(i->lazy),
658 i->filename ? i->filename : _("n/a"),
659 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
660
661 pa_xfree(pl);
662 }
663
664 static void simple_callback(pa_context *c, int success, void *userdata) {
665 if (!success) {
666 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
667 quit(1);
668 return;
669 }
670
671 complete_action();
672 }
673
674 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
675 if (idx == PA_INVALID_INDEX) {
676 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
677 quit(1);
678 return;
679 }
680
681 printf("%u\n", idx);
682
683 complete_action();
684 }
685
686 static void stream_state_callback(pa_stream *s, void *userdata) {
687 pa_assert(s);
688
689 switch (pa_stream_get_state(s)) {
690 case PA_STREAM_CREATING:
691 case PA_STREAM_READY:
692 break;
693
694 case PA_STREAM_TERMINATED:
695 drain();
696 break;
697
698 case PA_STREAM_FAILED:
699 default:
700 pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
701 quit(1);
702 }
703 }
704
705 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
706 sf_count_t l;
707 float *d;
708 pa_assert(s && length && sndfile);
709
710 d = pa_xmalloc(length);
711
712 pa_assert(sample_length >= length);
713 l = (sf_count_t) (length/pa_frame_size(&sample_spec));
714
715 if ((sf_readf_float(sndfile, d, l)) != l) {
716 pa_xfree(d);
717 pa_log(_("Premature end of file"));
718 quit(1);
719 return;
720 }
721
722 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
723
724 sample_length -= length;
725
726 if (sample_length <= 0) {
727 pa_stream_set_write_callback(sample_stream, NULL, NULL);
728 pa_stream_finish_upload(sample_stream);
729 }
730 }
731
732 static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) {
733
734 switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
735
736 case PA_SUBSCRIPTION_EVENT_NEW:
737 return _("new");
738
739 case PA_SUBSCRIPTION_EVENT_CHANGE:
740 return _("change");
741
742 case PA_SUBSCRIPTION_EVENT_REMOVE:
743 return _("remove");
744 }
745
746 return _("unknown");
747 }
748
749 static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) {
750
751 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
752
753 case PA_SUBSCRIPTION_EVENT_SINK:
754 return _("sink");
755
756 case PA_SUBSCRIPTION_EVENT_SOURCE:
757 return _("source");
758
759 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
760 return _("sink-input");
761
762 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
763 return _("source-output");
764
765 case PA_SUBSCRIPTION_EVENT_MODULE:
766 return _("module");
767
768 case PA_SUBSCRIPTION_EVENT_CLIENT:
769 return _("client");
770
771 case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
772 return _("sample-cache");
773
774 case PA_SUBSCRIPTION_EVENT_SERVER:
775 return _("server");
776
777 case PA_SUBSCRIPTION_EVENT_CARD:
778 return _("server");
779 }
780
781 return _("unknown");
782 }
783
784 static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
785 pa_assert(c);
786
787 printf(_("Event '%s' on %s #%u\n"),
788 subscription_event_type_to_string(t),
789 subscription_event_facility_to_string(t),
790 idx);
791 }
792
793 static void context_state_callback(pa_context *c, void *userdata) {
794 pa_assert(c);
795 switch (pa_context_get_state(c)) {
796 case PA_CONTEXT_CONNECTING:
797 case PA_CONTEXT_AUTHORIZING:
798 case PA_CONTEXT_SETTING_NAME:
799 break;
800
801 case PA_CONTEXT_READY:
802 switch (action) {
803 case STAT:
804 actions = 2;
805 pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
806 pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
807 break;
808
809 case PLAY_SAMPLE:
810 pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL));
811 break;
812
813 case REMOVE_SAMPLE:
814 pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
815 break;
816
817 case UPLOAD_SAMPLE:
818 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
819 pa_assert(sample_stream);
820
821 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
822 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
823 pa_stream_connect_upload(sample_stream, sample_length);
824 break;
825
826 case EXIT:
827 pa_operation_unref(pa_context_exit_daemon(c, simple_callback, NULL));
828 break;
829
830 case LIST:
831 actions = 8;
832 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
833 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
834 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
835 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
836 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
837 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
838 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
839 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
840 break;
841
842 case MOVE_SINK_INPUT:
843 pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL));
844 break;
845
846 case MOVE_SOURCE_OUTPUT:
847 pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
848 break;
849
850 case LOAD_MODULE:
851 pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
852 break;
853
854 case UNLOAD_MODULE:
855 pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
856 break;
857
858 case SUSPEND_SINK:
859 if (sink_name)
860 pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
861 else
862 pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
863 break;
864
865 case SUSPEND_SOURCE:
866 if (source_name)
867 pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
868 else
869 pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
870 break;
871
872 case SET_CARD_PROFILE:
873 pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
874 break;
875
876 case SET_SINK_PORT:
877 pa_operation_unref(pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL));
878 break;
879
880 case SET_SOURCE_PORT:
881 pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL));
882 break;
883
884 case SET_SINK_MUTE:
885 pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL));
886 break;
887
888 case SET_SOURCE_MUTE:
889 pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL));
890 break;
891
892 case SET_SINK_INPUT_MUTE:
893 pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
894 break;
895
896 case SET_SINK_VOLUME: {
897 pa_cvolume v;
898
899 pa_cvolume_set(&v, 1, volume);
900 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
901 break;
902 }
903
904 case SET_SOURCE_VOLUME: {
905 pa_cvolume v;
906
907 pa_cvolume_set(&v, 1, volume);
908 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
909 break;
910 }
911
912 case SET_SINK_INPUT_VOLUME: {
913 pa_cvolume v;
914
915 pa_cvolume_set(&v, 1, volume);
916 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
917 break;
918 }
919
920 case SUBSCRIBE:
921 pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
922
923 pa_operation_unref(pa_context_subscribe(
924 c,
925 PA_SUBSCRIPTION_MASK_SINK|
926 PA_SUBSCRIPTION_MASK_SOURCE|
927 PA_SUBSCRIPTION_MASK_SINK_INPUT|
928 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
929 PA_SUBSCRIPTION_MASK_MODULE|
930 PA_SUBSCRIPTION_MASK_CLIENT|
931 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
932 PA_SUBSCRIPTION_MASK_SERVER|
933 PA_SUBSCRIPTION_MASK_CARD,
934 NULL,
935 NULL));
936 break;
937
938 default:
939 pa_assert_not_reached();
940 }
941 break;
942
943 case PA_CONTEXT_TERMINATED:
944 quit(0);
945 break;
946
947 case PA_CONTEXT_FAILED:
948 default:
949 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
950 quit(1);
951 }
952 }
953
954 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
955 pa_log(_("Got SIGINT, exiting."));
956 quit(0);
957 }
958
959 static void help(const char *argv0) {
960
961 printf(_("%s [options] stat\n"
962 "%s [options] list\n"
963 "%s [options] exit\n"
964 "%s [options] upload-sample FILENAME [NAME]\n"
965 "%s [options] play-sample NAME [SINK]\n"
966 "%s [options] remove-sample NAME\n"
967 "%s [options] move-sink-input SINKINPUT SINK\n"
968 "%s [options] move-source-output SOURCEOUTPUT SOURCE\n"
969 "%s [options] load-module NAME [ARGS ...]\n"
970 "%s [options] unload-module MODULE\n"
971 "%s [options] suspend-sink SINK 1|0\n"
972 "%s [options] suspend-source SOURCE 1|0\n"
973 "%s [options] set-card-profile CARD PROFILE\n"
974 "%s [options] set-sink-port SINK PORT\n"
975 "%s [options] set-source-port SOURCE PORT\n"
976 "%s [options] set-sink-volume SINK VOLUME\n"
977 "%s [options] set-source-volume SOURCE VOLUME\n"
978 "%s [options] set-sink-input-volume SINKINPUT VOLUME\n"
979 "%s [options] set-sink-mute SINK 1|0\n"
980 "%s [options] set-source-mute SOURCE 1|0\n"
981 "%s [options] set-sink-input-mute SINKINPUT 1|0\n"
982 "%s [options] subscribe\n\n"
983 " -h, --help Show this help\n"
984 " --version Show version\n\n"
985 " -s, --server=SERVER The name of the server to connect to\n"
986 " -n, --client-name=NAME How to call this client on the server\n"),
987 argv0, argv0, argv0, argv0, argv0,
988 argv0, argv0, argv0, argv0, argv0,
989 argv0, argv0, argv0, argv0, argv0,
990 argv0, argv0, argv0, argv0, argv0,
991 argv0, argv0);
992 }
993
994 enum {
995 ARG_VERSION = 256
996 };
997
998 int main(int argc, char *argv[]) {
999 pa_mainloop* m = NULL;
1000 int ret = 1, c;
1001 char *server = NULL, *bn;
1002
1003 static const struct option long_options[] = {
1004 {"server", 1, NULL, 's'},
1005 {"client-name", 1, NULL, 'n'},
1006 {"version", 0, NULL, ARG_VERSION},
1007 {"help", 0, NULL, 'h'},
1008 {NULL, 0, NULL, 0}
1009 };
1010
1011 setlocale(LC_ALL, "");
1012 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
1013
1014 bn = pa_path_get_filename(argv[0]);
1015
1016 proplist = pa_proplist_new();
1017
1018 while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
1019 switch (c) {
1020 case 'h' :
1021 help(bn);
1022 ret = 0;
1023 goto quit;
1024
1025 case ARG_VERSION:
1026 printf(_("pactl %s\n"
1027 "Compiled with libpulse %s\n"
1028 "Linked with libpulse %s\n"),
1029 PACKAGE_VERSION,
1030 pa_get_headers_version(),
1031 pa_get_library_version());
1032 ret = 0;
1033 goto quit;
1034
1035 case 's':
1036 pa_xfree(server);
1037 server = pa_xstrdup(optarg);
1038 break;
1039
1040 case 'n': {
1041 char *t;
1042
1043 if (!(t = pa_locale_to_utf8(optarg)) ||
1044 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
1045
1046 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
1047 pa_xfree(t);
1048 goto quit;
1049 }
1050
1051 pa_xfree(t);
1052 break;
1053 }
1054
1055 default:
1056 goto quit;
1057 }
1058 }
1059
1060 if (optind < argc) {
1061 if (pa_streq(argv[optind], "stat"))
1062 action = STAT;
1063 else if (pa_streq(argv[optind], "exit"))
1064 action = EXIT;
1065 else if (pa_streq(argv[optind], "list"))
1066 action = LIST;
1067 else if (pa_streq(argv[optind], "upload-sample")) {
1068 struct SF_INFO sfi;
1069 action = UPLOAD_SAMPLE;
1070
1071 if (optind+1 >= argc) {
1072 pa_log(_("Please specify a sample file to load"));
1073 goto quit;
1074 }
1075
1076 if (optind+2 < argc)
1077 sample_name = pa_xstrdup(argv[optind+2]);
1078 else {
1079 char *f = pa_path_get_filename(argv[optind+1]);
1080 sample_name = pa_xstrndup(f, strcspn(f, "."));
1081 }
1082
1083 pa_zero(sfi);
1084 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
1085 pa_log(_("Failed to open sound file."));
1086 goto quit;
1087 }
1088
1089 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1090 pa_log(_("Failed to determine sample specification from file."));
1091 goto quit;
1092 }
1093 sample_spec.format = PA_SAMPLE_FLOAT32;
1094
1095 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1096 if (sample_spec.channels > 2)
1097 pa_log(_("Warning: Failed to determine sample specification from file."));
1098 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1099 }
1100
1101 pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
1102 sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
1103
1104 } else if (pa_streq(argv[optind], "play-sample")) {
1105 action = PLAY_SAMPLE;
1106 if (argc != optind+2 && argc != optind+3) {
1107 pa_log(_("You have to specify a sample name to play"));
1108 goto quit;
1109 }
1110
1111 sample_name = pa_xstrdup(argv[optind+1]);
1112
1113 if (optind+2 < argc)
1114 sink_name = pa_xstrdup(argv[optind+2]);
1115
1116 } else if (pa_streq(argv[optind], "remove-sample")) {
1117 action = REMOVE_SAMPLE;
1118 if (argc != optind+2) {
1119 pa_log(_("You have to specify a sample name to remove"));
1120 goto quit;
1121 }
1122
1123 sample_name = pa_xstrdup(argv[optind+1]);
1124
1125 } else if (pa_streq(argv[optind], "move-sink-input")) {
1126 action = MOVE_SINK_INPUT;
1127 if (argc != optind+3) {
1128 pa_log(_("You have to specify a sink input index and a sink"));
1129 goto quit;
1130 }
1131
1132 sink_input_idx = (uint32_t) atoi(argv[optind+1]);
1133 sink_name = pa_xstrdup(argv[optind+2]);
1134
1135 } else if (pa_streq(argv[optind], "move-source-output")) {
1136 action = MOVE_SOURCE_OUTPUT;
1137 if (argc != optind+3) {
1138 pa_log(_("You have to specify a source output index and a source"));
1139 goto quit;
1140 }
1141
1142 source_output_idx = (uint32_t) atoi(argv[optind+1]);
1143 source_name = pa_xstrdup(argv[optind+2]);
1144
1145 } else if (pa_streq(argv[optind], "load-module")) {
1146 int i;
1147 size_t n = 0;
1148 char *p;
1149
1150 action = LOAD_MODULE;
1151
1152 if (argc <= optind+1) {
1153 pa_log(_("You have to specify a module name and arguments."));
1154 goto quit;
1155 }
1156
1157 module_name = argv[optind+1];
1158
1159 for (i = optind+2; i < argc; i++)
1160 n += strlen(argv[i])+1;
1161
1162 if (n > 0) {
1163 p = module_args = pa_xmalloc(n);
1164
1165 for (i = optind+2; i < argc; i++)
1166 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
1167 }
1168
1169 } else if (pa_streq(argv[optind], "unload-module")) {
1170 action = UNLOAD_MODULE;
1171
1172 if (argc != optind+2) {
1173 pa_log(_("You have to specify a module index"));
1174 goto quit;
1175 }
1176
1177 module_index = (uint32_t) atoi(argv[optind+1]);
1178
1179 } else if (pa_streq(argv[optind], "suspend-sink")) {
1180 action = SUSPEND_SINK;
1181
1182 if (argc > optind+3 || optind+1 >= argc) {
1183 pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
1184 goto quit;
1185 }
1186
1187 suspend = pa_parse_boolean(argv[argc-1]);
1188
1189 if (argc > optind+2)
1190 sink_name = pa_xstrdup(argv[optind+1]);
1191
1192 } else if (pa_streq(argv[optind], "suspend-source")) {
1193 action = SUSPEND_SOURCE;
1194
1195 if (argc > optind+3 || optind+1 >= argc) {
1196 pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
1197 goto quit;
1198 }
1199
1200 suspend = pa_parse_boolean(argv[argc-1]);
1201
1202 if (argc > optind+2)
1203 source_name = pa_xstrdup(argv[optind+1]);
1204 } else if (pa_streq(argv[optind], "set-card-profile")) {
1205 action = SET_CARD_PROFILE;
1206
1207 if (argc != optind+3) {
1208 pa_log(_("You have to specify a card name/index and a profile name"));
1209 goto quit;
1210 }
1211
1212 card_name = pa_xstrdup(argv[optind+1]);
1213 profile_name = pa_xstrdup(argv[optind+2]);
1214
1215 } else if (pa_streq(argv[optind], "set-sink-port")) {
1216 action = SET_SINK_PORT;
1217
1218 if (argc != optind+3) {
1219 pa_log(_("You have to specify a sink name/index and a port name"));
1220 goto quit;
1221 }
1222
1223 sink_name = pa_xstrdup(argv[optind+1]);
1224 port_name = pa_xstrdup(argv[optind+2]);
1225
1226 } else if (pa_streq(argv[optind], "set-source-port")) {
1227 action = SET_SOURCE_PORT;
1228
1229 if (argc != optind+3) {
1230 pa_log(_("You have to specify a source name/index and a port name"));
1231 goto quit;
1232 }
1233
1234 source_name = pa_xstrdup(argv[optind+1]);
1235 port_name = pa_xstrdup(argv[optind+2]);
1236
1237 } else if (pa_streq(argv[optind], "set-sink-volume")) {
1238 uint32_t v;
1239 action = SET_SINK_VOLUME;
1240
1241 if (argc != optind+3) {
1242 pa_log(_("You have to specify a sink name/index and a volume"));
1243 goto quit;
1244 }
1245
1246 if (pa_atou(argv[optind+2], &v) < 0) {
1247 pa_log(_("Invalid volume specification"));
1248 goto quit;
1249 }
1250
1251 sink_name = pa_xstrdup(argv[optind+1]);
1252 volume = (pa_volume_t) v;
1253
1254 } else if (pa_streq(argv[optind], "set-source-volume")) {
1255 uint32_t v;
1256 action = SET_SOURCE_VOLUME;
1257
1258 if (argc != optind+3) {
1259 pa_log(_("You have to specify a source name/index and a volume"));
1260 goto quit;
1261 }
1262
1263 if (pa_atou(argv[optind+2], &v) < 0) {
1264 pa_log(_("Invalid volume specification"));
1265 goto quit;
1266 }
1267
1268 source_name = pa_xstrdup(argv[optind+1]);
1269 volume = (pa_volume_t) v;
1270
1271 } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
1272 uint32_t v;
1273 action = SET_SINK_INPUT_VOLUME;
1274
1275 if (argc != optind+3) {
1276 pa_log(_("You have to specify a sink input index and a volume"));
1277 goto quit;
1278 }
1279
1280 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1281 pa_log(_("Invalid sink input index"));
1282 goto quit;
1283 }
1284
1285 if (pa_atou(argv[optind+2], &v) < 0) {
1286 pa_log(_("Invalid volume specification"));
1287 goto quit;
1288 }
1289
1290 volume = (pa_volume_t) v;
1291
1292 } else if (pa_streq(argv[optind], "set-sink-mute")) {
1293 int b;
1294 action = SET_SINK_MUTE;
1295
1296 if (argc != optind+3) {
1297 pa_log(_("You have to specify a sink name/index and a mute boolean"));
1298 goto quit;
1299 }
1300
1301 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1302 pa_log(_("Invalid volume specification"));
1303 goto quit;
1304 }
1305
1306 sink_name = pa_xstrdup(argv[optind+1]);
1307 mute = b;
1308
1309 } else if (pa_streq(argv[optind], "set-source-mute")) {
1310 int b;
1311 action = SET_SOURCE_MUTE;
1312
1313 if (argc != optind+3) {
1314 pa_log(_("You have to specify a source name/index and a mute boolean"));
1315 goto quit;
1316 }
1317
1318 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1319 pa_log(_("Invalid volume specification"));
1320 goto quit;
1321 }
1322
1323 source_name = pa_xstrdup(argv[optind+1]);
1324 mute = b;
1325
1326 } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
1327 int b;
1328 action = SET_SINK_INPUT_MUTE;
1329
1330 if (argc != optind+3) {
1331 pa_log(_("You have to specify a sink input index and a mute boolean"));
1332 goto quit;
1333 }
1334
1335 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1336 pa_log(_("Invalid sink input index specification"));
1337 goto quit;
1338 }
1339
1340 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1341 pa_log(_("Invalid volume specification"));
1342 goto quit;
1343 }
1344
1345 mute = b;
1346
1347 } else if (pa_streq(argv[optind], "subscribe"))
1348
1349 action = SUBSCRIBE;
1350
1351 else if (pa_streq(argv[optind], "help")) {
1352 help(bn);
1353 ret = 0;
1354 goto quit;
1355 }
1356 }
1357
1358 if (action == NONE) {
1359 pa_log(_("No valid command specified."));
1360 goto quit;
1361 }
1362
1363 if (!(m = pa_mainloop_new())) {
1364 pa_log(_("pa_mainloop_new() failed."));
1365 goto quit;
1366 }
1367
1368 mainloop_api = pa_mainloop_get_api(m);
1369
1370 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1371 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1372 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1373 pa_disable_sigpipe();
1374
1375 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1376 pa_log(_("pa_context_new() failed."));
1377 goto quit;
1378 }
1379
1380 pa_context_set_state_callback(context, context_state_callback, NULL);
1381 if (pa_context_connect(context, server, 0, NULL) < 0) {
1382 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1383 goto quit;
1384 }
1385
1386 if (pa_mainloop_run(m, &ret) < 0) {
1387 pa_log(_("pa_mainloop_run() failed."));
1388 goto quit;
1389 }
1390
1391 quit:
1392 if (sample_stream)
1393 pa_stream_unref(sample_stream);
1394
1395 if (context)
1396 pa_context_unref(context);
1397
1398 if (m) {
1399 pa_signal_done();
1400 pa_mainloop_free(m);
1401 }
1402
1403 pa_xfree(server);
1404 pa_xfree(sample_name);
1405 pa_xfree(sink_name);
1406 pa_xfree(source_name);
1407 pa_xfree(module_args);
1408 pa_xfree(card_name);
1409 pa_xfree(profile_name);
1410
1411 if (sndfile)
1412 sf_close(sndfile);
1413
1414 if (proplist)
1415 pa_proplist_free(proplist);
1416
1417 return ret;
1418 }