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