]> code.delx.au - pulseaudio/blob - src/utils/pactl.c
Merge dead branch 'glitch-free'
[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 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
36 #include <sndfile.h>
37
38 #include <pulse/pulseaudio.h>
39 #include <pulsecore/core-util.h>
40
41 #if PA_API_VERSION < 10
42 #error Invalid PulseAudio API version
43 #endif
44
45 #define BUFSIZE 1024
46
47 static pa_context *context = NULL;
48 static pa_mainloop_api *mainloop_api = NULL;
49
50 static char *device = NULL, *sample_name = NULL, *sink_name = NULL, *source_name = NULL, *module_name = NULL, *module_args = NULL;
51 static uint32_t sink_input_idx = PA_INVALID_INDEX, source_output_idx = PA_INVALID_INDEX;
52 static uint32_t module_index;
53 static int suspend;
54
55 static SNDFILE *sndfile = NULL;
56 static pa_stream *sample_stream = NULL;
57 static pa_sample_spec sample_spec;
58 static size_t sample_length = 0;
59
60 static int actions = 1;
61
62 static int nl = 0;
63
64 static enum {
65 NONE,
66 EXIT,
67 STAT,
68 UPLOAD_SAMPLE,
69 PLAY_SAMPLE,
70 REMOVE_SAMPLE,
71 LIST,
72 MOVE_SINK_INPUT,
73 MOVE_SOURCE_OUTPUT,
74 LOAD_MODULE,
75 UNLOAD_MODULE,
76 SUSPEND_SINK,
77 SUSPEND_SOURCE,
78 } action = NONE;
79
80 static void quit(int ret) {
81 assert(mainloop_api);
82 mainloop_api->quit(mainloop_api, ret);
83 }
84
85
86 static void context_drain_complete(pa_context *c, void *userdata) {
87 pa_context_disconnect(c);
88 }
89
90 static void drain(void) {
91 pa_operation *o;
92 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
93 pa_context_disconnect(context);
94 else
95 pa_operation_unref(o);
96 }
97
98
99 static void complete_action(void) {
100 assert(actions > 0);
101
102 if (!(--actions))
103 drain();
104 }
105
106 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
107 char s[128];
108 if (!i) {
109 fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c)));
110 quit(1);
111 return;
112 }
113
114 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
115 printf("Currently in use: %u blocks containing %s bytes total.\n", i->memblock_total, s);
116
117 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
118 printf("Allocated during whole lifetime: %u blocks containing %s bytes total.\n", i->memblock_allocated, s);
119
120 pa_bytes_snprint(s, sizeof(s), i->scache_size);
121 printf("Sample cache size: %s\n", s);
122
123 complete_action();
124 }
125
126 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
127 char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
128
129 if (!i) {
130 fprintf(stderr, "Failed to get server information: %s\n", pa_strerror(pa_context_errno(c)));
131 quit(1);
132 return;
133 }
134
135 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
136
137 printf("User name: %s\n"
138 "Host Name: %s\n"
139 "Server Name: %s\n"
140 "Server Version: %s\n"
141 "Default Sample Specification: %s\n"
142 "Default Sink: %s\n"
143 "Default Source: %s\n"
144 "Cookie: %08x\n",
145 i->user_name,
146 i->host_name,
147 i->server_name,
148 i->server_version,
149 s,
150 i->default_sink_name,
151 i->default_source_name,
152 i->cookie);
153
154 complete_action();
155 }
156
157 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
158 char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
159 char *pl;
160
161 if (is_last < 0) {
162 fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c)));
163 quit(1);
164 return;
165 }
166
167 if (is_last) {
168 complete_action();
169 return;
170 }
171
172 assert(i);
173
174 if (nl)
175 printf("\n");
176 nl = 1;
177
178 printf("*** Sink #%u ***\n"
179 "Name: %s\n"
180 "Driver: %s\n"
181 "Sample Specification: %s\n"
182 "Channel Map: %s\n"
183 "Owner Module: %u\n"
184 "Volume: %s\n"
185 "Monitor Source: %s\n"
186 "Latency: %0.0f usec, configured %0.0f usec\n"
187 "Flags: %s%s%s%s%s%s\n"
188 "Properties:\n%s",
189 i->index,
190 i->name,
191 pa_strnull(i->driver),
192 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
193 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
194 i->owner_module,
195 i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
196 pa_strnull(i->monitor_source_name),
197 (double) i->latency, (double) i->configured_latency,
198 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
199 i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
200 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
201 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
202 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
203 i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
204 pl = pa_proplist_to_string(i->proplist));
205
206 pa_xfree(pl);
207 }
208
209 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
210 char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
211 char *pl;
212
213 if (is_last < 0) {
214 fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c)));
215 quit(1);
216 return;
217 }
218
219 if (is_last) {
220 complete_action();
221 return;
222 }
223
224 assert(i);
225
226 if (nl)
227 printf("\n");
228 nl = 1;
229
230 printf("*** Source #%u ***\n"
231 "Name: %s\n"
232 "Driver: %s\n"
233 "Sample Specification: %s\n"
234 "Channel Map: %s\n"
235 "Owner Module: %u\n"
236 "Volume: %s\n"
237 "Monitor of Sink: %s\n"
238 "Latency: %0.0f usec, configured %0.0f usec\n"
239 "Flags: %s%s%s%s%s%s\n"
240 "Properties:\n%s",
241 i->index,
242 i->name,
243 pa_strnull(i->driver),
244 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
245 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
246 i->owner_module,
247 i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
248 i->monitor_of_sink_name ? i->monitor_of_sink_name : "n/a",
249 (double) i->latency, (double) i->configured_latency,
250 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
251 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
252 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
253 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
254 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
255 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
256 pl = pa_proplist_to_string(i->proplist));
257
258 pa_xfree(pl);
259 }
260
261 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
262 char t[32];
263
264 if (is_last < 0) {
265 fprintf(stderr, "Failed to get module information: %s\n", pa_strerror(pa_context_errno(c)));
266 quit(1);
267 return;
268 }
269
270 if (is_last) {
271 complete_action();
272 return;
273 }
274
275 assert(i);
276
277 if (nl)
278 printf("\n");
279 nl = 1;
280
281 snprintf(t, sizeof(t), "%u", i->n_used);
282
283 printf("*** Module #%u ***\n"
284 "Name: %s\n"
285 "Argument: %s\n"
286 "Usage counter: %s\n"
287 "Auto unload: %s\n",
288 i->index,
289 i->name,
290 i->argument ? i->argument : "",
291 i->n_used != PA_INVALID_INDEX ? t : "n/a",
292 pa_yes_no(i->auto_unload));
293 }
294
295 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
296 char t[32];
297 char *pl;
298
299 if (is_last < 0) {
300 fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c)));
301 quit(1);
302 return;
303 }
304
305 if (is_last) {
306 complete_action();
307 return;
308 }
309
310 assert(i);
311
312 if (nl)
313 printf("\n");
314 nl = 1;
315
316 snprintf(t, sizeof(t), "%u", i->owner_module);
317
318 printf("*** Client #%u ***\n"
319 "Driver: %s\n"
320 "Owner Module: %s\n"
321 "Properties:\n%s",
322 i->index,
323 pa_strnull(i->driver),
324 i->owner_module != PA_INVALID_INDEX ? t : "n/a",
325 pl = pa_proplist_to_string(i->proplist));
326
327 pa_xfree(pl);
328 }
329
330 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
331 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
332 char *pl;
333
334 if (is_last < 0) {
335 fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c)));
336 quit(1);
337 return;
338 }
339
340 if (is_last) {
341 complete_action();
342 return;
343 }
344
345 assert(i);
346
347 if (nl)
348 printf("\n");
349 nl = 1;
350
351 snprintf(t, sizeof(t), "%u", i->owner_module);
352 snprintf(k, sizeof(k), "%u", i->client);
353
354 printf("*** Sink Input #%u ***\n"
355 "Driver: %s\n"
356 "Owner Module: %s\n"
357 "Client: %s\n"
358 "Sink: %u\n"
359 "Sample Specification: %s\n"
360 "Channel Map: %s\n"
361 "Volume: %s\n"
362 "Buffer Latency: %0.0f usec\n"
363 "Sink Latency: %0.0f usec\n"
364 "Resample method: %s\n"
365 "Properties:\n%s",
366 i->index,
367 pa_strnull(i->driver),
368 i->owner_module != PA_INVALID_INDEX ? t : "n/a",
369 i->client != PA_INVALID_INDEX ? k : "n/a",
370 i->sink,
371 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
372 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
373 i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
374 (double) i->buffer_usec,
375 (double) i->sink_usec,
376 i->resample_method ? i->resample_method : "n/a",
377 pl = pa_proplist_to_string(i->proplist));
378
379 pa_xfree(pl);
380 }
381
382 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
383 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
384 char *pl;
385
386 if (is_last < 0) {
387 fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c)));
388 quit(1);
389 return;
390 }
391
392 if (is_last) {
393 complete_action();
394 return;
395 }
396
397 assert(i);
398
399 if (nl)
400 printf("\n");
401 nl = 1;
402
403
404 snprintf(t, sizeof(t), "%u", i->owner_module);
405 snprintf(k, sizeof(k), "%u", i->client);
406
407 printf("*** Source Output #%u ***\n"
408 "Driver: %s\n"
409 "Owner Module: %s\n"
410 "Client: %s\n"
411 "Source: %u\n"
412 "Sample Specification: %s\n"
413 "Channel Map: %s\n"
414 "Buffer Latency: %0.0f usec\n"
415 "Source Latency: %0.0f usec\n"
416 "Resample method: %s\n"
417 "Properties:\n%s",
418 i->index,
419 pa_strnull(i->driver),
420 i->owner_module != PA_INVALID_INDEX ? t : "n/a",
421 i->client != PA_INVALID_INDEX ? k : "n/a",
422 i->source,
423 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
424 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
425 (double) i->buffer_usec,
426 (double) i->source_usec,
427 i->resample_method ? i->resample_method : "n/a",
428 pl = pa_proplist_to_string(i->proplist));
429
430 pa_xfree(pl);
431 }
432
433 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
434 char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
435 char *pl;
436
437 if (is_last < 0) {
438 fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c)));
439 quit(1);
440 return;
441 }
442
443 if (is_last) {
444 complete_action();
445 return;
446 }
447
448 assert(i);
449
450 if (nl)
451 printf("\n");
452 nl = 1;
453
454
455 pa_bytes_snprint(t, sizeof(t), i->bytes);
456
457 printf("*** Sample #%u ***\n"
458 "Name: %s\n"
459 "Volume: %s\n"
460 "Sample Specification: %s\n"
461 "Channel Map: %s\n"
462 "Duration: %0.1fs\n"
463 "Size: %s\n"
464 "Lazy: %s\n"
465 "Filename: %s\n"
466 "Properties:\n%s",
467 i->index,
468 i->name,
469 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
470 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "n/a",
471 pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : "n/a",
472 (double) i->duration/1000000,
473 t,
474 pa_yes_no(i->lazy),
475 i->filename ? i->filename : "n/a",
476 pl = pa_proplist_to_string(i->proplist));
477
478 pa_xfree(pl);
479 }
480
481 static void get_autoload_info_callback(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata) {
482 if (is_last < 0) {
483 fprintf(stderr, "Failed to get autoload information: %s\n", pa_strerror(pa_context_errno(c)));
484 quit(1);
485 return;
486 }
487
488 if (is_last) {
489 complete_action();
490 return;
491 }
492
493 assert(i);
494
495 if (nl)
496 printf("\n");
497 nl = 1;
498
499 printf("*** Autoload Entry #%u ***\n"
500 "Name: %s\n"
501 "Type: %s\n"
502 "Module: %s\n"
503 "Argument: %s\n",
504 i->index,
505 i->name,
506 i->type == PA_AUTOLOAD_SINK ? "sink" : "source",
507 i->module,
508 i->argument ? i->argument : "");
509 }
510
511 static void simple_callback(pa_context *c, int success, void *userdata) {
512 if (!success) {
513 fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c)));
514 quit(1);
515 return;
516 }
517
518 complete_action();
519 }
520
521 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
522 if (idx == PA_INVALID_INDEX) {
523 fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c)));
524 quit(1);
525 return;
526 }
527
528 printf("%u\n", idx);
529
530 complete_action();
531 }
532
533 static void stream_state_callback(pa_stream *s, void *userdata) {
534 assert(s);
535
536 switch (pa_stream_get_state(s)) {
537 case PA_STREAM_CREATING:
538 case PA_STREAM_READY:
539 break;
540
541 case PA_STREAM_TERMINATED:
542 drain();
543 break;
544
545 case PA_STREAM_FAILED:
546 default:
547 fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
548 quit(1);
549 }
550 }
551
552 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
553 sf_count_t l;
554 float *d;
555 assert(s && length && sndfile);
556
557 d = pa_xmalloc(length);
558
559 assert(sample_length >= length);
560 l = length/pa_frame_size(&sample_spec);
561
562 if ((sf_readf_float(sndfile, d, l)) != l) {
563 pa_xfree(d);
564 fprintf(stderr, "Premature end of file\n");
565 quit(1);
566 }
567
568 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
569
570 sample_length -= length;
571
572 if (sample_length <= 0) {
573 pa_stream_set_write_callback(sample_stream, NULL, NULL);
574 pa_stream_finish_upload(sample_stream);
575 }
576 }
577
578 static void context_state_callback(pa_context *c, void *userdata) {
579 assert(c);
580 switch (pa_context_get_state(c)) {
581 case PA_CONTEXT_CONNECTING:
582 case PA_CONTEXT_AUTHORIZING:
583 case PA_CONTEXT_SETTING_NAME:
584 break;
585
586 case PA_CONTEXT_READY:
587 switch (action) {
588 case STAT:
589 actions = 2;
590 pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
591 pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
592 break;
593
594 case PLAY_SAMPLE:
595 pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL));
596 break;
597
598 case REMOVE_SAMPLE:
599 pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
600 break;
601
602 case UPLOAD_SAMPLE:
603 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
604 assert(sample_stream);
605
606 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
607 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
608 pa_stream_connect_upload(sample_stream, sample_length);
609 break;
610
611 case EXIT:
612 pa_operation_unref(pa_context_exit_daemon(c, NULL, NULL));
613 drain();
614
615 case LIST:
616 actions = 8;
617 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
618 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
619 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
620 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
621 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
622 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
623 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
624 pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL));
625 break;
626
627 case MOVE_SINK_INPUT:
628 pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL));
629 break;
630
631 case MOVE_SOURCE_OUTPUT:
632 pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
633 break;
634
635 case LOAD_MODULE:
636 pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
637 break;
638
639 case UNLOAD_MODULE:
640 pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
641 break;
642
643 case SUSPEND_SINK:
644 if (sink_name)
645 pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
646 else
647 pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
648 break;
649
650 case SUSPEND_SOURCE:
651 if (source_name)
652 pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
653 else
654 pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
655 break;
656
657 default:
658 assert(0);
659 }
660 break;
661
662 case PA_CONTEXT_TERMINATED:
663 quit(0);
664 break;
665
666 case PA_CONTEXT_FAILED:
667 default:
668 fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c)));
669 quit(1);
670 }
671 }
672
673 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
674 fprintf(stderr, "Got SIGINT, exiting.\n");
675 quit(0);
676 }
677
678 static void help(const char *argv0) {
679
680 printf("%s [options] stat\n"
681 "%s [options] list\n"
682 "%s [options] exit\n"
683 "%s [options] upload-sample FILENAME [NAME]\n"
684 "%s [options] play-sample NAME [SINK]\n"
685 "%s [options] remove-sample NAME\n"
686 "%s [options] move-sink-input ID SINK\n"
687 "%s [options] move-source-output ID SOURCE\n"
688 "%s [options] load-module NAME [ARGS ...]\n"
689 "%s [options] unload-module ID\n"
690 "%s [options] suspend-sink [SINK] 1|0\n"
691 "%s [options] suspend-source [SOURCE] 1|0\n\n"
692 " -h, --help Show this help\n"
693 " --version Show version\n\n"
694 " -s, --server=SERVER The name of the server to connect to\n"
695 " -n, --client-name=NAME How to call this client on the server\n",
696 argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0, argv0);
697 }
698
699 enum { ARG_VERSION = 256 };
700
701 int main(int argc, char *argv[]) {
702 pa_mainloop* m = NULL;
703 char tmp[PATH_MAX];
704 int ret = 1, r, c;
705 char *server = NULL, *client_name = NULL, *bn;
706
707 static const struct option long_options[] = {
708 {"server", 1, NULL, 's'},
709 {"client-name", 1, NULL, 'n'},
710 {"version", 0, NULL, ARG_VERSION},
711 {"help", 0, NULL, 'h'},
712 {NULL, 0, NULL, 0}
713 };
714
715 if (!(bn = strrchr(argv[0], '/')))
716 bn = argv[0];
717 else
718 bn++;
719
720 while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
721 switch (c) {
722 case 'h' :
723 help(bn);
724 ret = 0;
725 goto quit;
726
727 case ARG_VERSION:
728 printf("pactl "PACKAGE_VERSION"\nCompiled with libpulse %s\nLinked with libpulse %s\n", pa_get_headers_version(), pa_get_library_version());
729 ret = 0;
730 goto quit;
731
732 case 's':
733 pa_xfree(server);
734 server = pa_xstrdup(optarg);
735 break;
736
737 case 'n':
738 pa_xfree(client_name);
739 client_name = pa_xstrdup(optarg);
740 break;
741
742 default:
743 goto quit;
744 }
745 }
746
747 if (!client_name)
748 client_name = pa_xstrdup(bn);
749
750 if (optind < argc) {
751 if (!strcmp(argv[optind], "stat"))
752 action = STAT;
753 else if (!strcmp(argv[optind], "exit"))
754 action = EXIT;
755 else if (!strcmp(argv[optind], "list"))
756 action = LIST;
757 else if (!strcmp(argv[optind], "upload-sample")) {
758 struct SF_INFO sfinfo;
759 action = UPLOAD_SAMPLE;
760
761 if (optind+1 >= argc) {
762 fprintf(stderr, "Please specify a sample file to load\n");
763 goto quit;
764 }
765
766 if (optind+2 < argc)
767 sample_name = pa_xstrdup(argv[optind+2]);
768 else {
769 char *f = strrchr(argv[optind+1], '/');
770 size_t n;
771 if (f)
772 f++;
773 else
774 f = argv[optind];
775
776 n = strcspn(f, ".");
777 strncpy(tmp, f, n);
778 tmp[n] = 0;
779 sample_name = pa_xstrdup(tmp);
780 }
781
782 memset(&sfinfo, 0, sizeof(sfinfo));
783 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) {
784 fprintf(stderr, "Failed to open sound file.\n");
785 goto quit;
786 }
787
788 sample_spec.format = PA_SAMPLE_FLOAT32;
789 sample_spec.rate = sfinfo.samplerate;
790 sample_spec.channels = sfinfo.channels;
791
792 sample_length = sfinfo.frames*pa_frame_size(&sample_spec);
793 } else if (!strcmp(argv[optind], "play-sample")) {
794 action = PLAY_SAMPLE;
795 if (argc != optind+2 && argc != optind+3) {
796 fprintf(stderr, "You have to specify a sample name to play\n");
797 goto quit;
798 }
799
800 sample_name = pa_xstrdup(argv[optind+1]);
801
802 if (optind+2 < argc)
803 device = pa_xstrdup(argv[optind+2]);
804
805 } else if (!strcmp(argv[optind], "remove-sample")) {
806 action = REMOVE_SAMPLE;
807 if (argc != optind+2) {
808 fprintf(stderr, "You have to specify a sample name to remove\n");
809 goto quit;
810 }
811
812 sample_name = pa_xstrdup(argv[optind+1]);
813 } else if (!strcmp(argv[optind], "move-sink-input")) {
814 action = MOVE_SINK_INPUT;
815 if (argc != optind+3) {
816 fprintf(stderr, "You have to specify a sink input index and a sink\n");
817 goto quit;
818 }
819
820 sink_input_idx = atoi(argv[optind+1]);
821 sink_name = pa_xstrdup(argv[optind+2]);
822 } else if (!strcmp(argv[optind], "move-source-output")) {
823 action = MOVE_SOURCE_OUTPUT;
824 if (argc != optind+3) {
825 fprintf(stderr, "You have to specify a source output index and a source\n");
826 goto quit;
827 }
828
829 source_output_idx = atoi(argv[optind+1]);
830 source_name = pa_xstrdup(argv[optind+2]);
831 } else if (!strcmp(argv[optind], "load-module")) {
832 int i;
833 size_t n = 0;
834 char *p;
835
836 action = LOAD_MODULE;
837
838 if (argc <= optind+1) {
839 fprintf(stderr, "You have to specify a module name and arguments.\n");
840 goto quit;
841 }
842
843 module_name = argv[optind+1];
844
845 for (i = optind+2; i < argc; i++)
846 n += strlen(argv[i])+1;
847
848 if (n > 0) {
849 p = module_args = pa_xnew0(char, n);
850
851 for (i = optind+2; i < argc; i++)
852 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
853 }
854
855 } else if (!strcmp(argv[optind], "unload-module")) {
856 action = UNLOAD_MODULE;
857
858 if (argc != optind+2) {
859 fprintf(stderr, "You have to specify a module index\n");
860 goto quit;
861 }
862
863 module_index = atoi(argv[optind+1]);
864
865 } else if (!strcmp(argv[optind], "suspend-sink")) {
866 action = SUSPEND_SINK;
867
868 if (argc > optind+3 || optind+1 >= argc) {
869 fprintf(stderr, "You may not specify more than one sink. You have to specify at least one boolean value.\n");
870 goto quit;
871 }
872
873 suspend = pa_parse_boolean(argv[argc-1]);
874
875 if (argc > optind+2)
876 sink_name = pa_xstrdup(argv[optind+1]);
877
878 } else if (!strcmp(argv[optind], "suspend-source")) {
879 action = SUSPEND_SOURCE;
880
881 if (argc > optind+3 || optind+1 >= argc) {
882 fprintf(stderr, "You may not specify more than one source. You have to specify at least one boolean value.\n");
883 goto quit;
884 }
885
886 suspend = pa_parse_boolean(argv[argc-1]);
887
888 if (argc > optind+2)
889 source_name = pa_xstrdup(argv[optind+1]);
890 } else if (!strcmp(argv[optind], "help")) {
891 help(bn);
892 ret = 0;
893 goto quit;
894 }
895 }
896
897 if (action == NONE) {
898 fprintf(stderr, "No valid command specified.\n");
899 goto quit;
900 }
901
902 if (!(m = pa_mainloop_new())) {
903 fprintf(stderr, "pa_mainloop_new() failed.\n");
904 goto quit;
905 }
906
907 mainloop_api = pa_mainloop_get_api(m);
908
909 r = pa_signal_init(mainloop_api);
910 assert(r == 0);
911 pa_signal_new(SIGINT, exit_signal_callback, NULL);
912 #ifdef SIGPIPE
913 signal(SIGPIPE, SIG_IGN);
914 #endif
915
916 if (!(context = pa_context_new(mainloop_api, client_name))) {
917 fprintf(stderr, "pa_context_new() failed.\n");
918 goto quit;
919 }
920
921 pa_context_set_state_callback(context, context_state_callback, NULL);
922 pa_context_connect(context, server, 0, NULL);
923
924 if (pa_mainloop_run(m, &ret) < 0) {
925 fprintf(stderr, "pa_mainloop_run() failed.\n");
926 goto quit;
927 }
928
929 quit:
930 if (sample_stream)
931 pa_stream_unref(sample_stream);
932
933 if (context)
934 pa_context_unref(context);
935
936 if (m) {
937 pa_signal_done();
938 pa_mainloop_free(m);
939 }
940
941 if (sndfile)
942 sf_close(sndfile);
943
944 pa_xfree(server);
945 pa_xfree(device);
946 pa_xfree(sample_name);
947 pa_xfree(sink_name);
948 pa_xfree(source_name);
949 pa_xfree(module_args);
950 pa_xfree(client_name);
951
952 return ret;
953 }