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