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