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