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