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