]> code.delx.au - pulseaudio/blob - polyp/pactl.c
* fix include file names in installed header files
[pulseaudio] / polyp / pactl.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio 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 polypaudio 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 polypaudio; 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 <polyp/polyplib.h>
39 #include <polyp/polyplib-error.h>
40 #include <polyp/mainloop.h>
41 #include <polyp/mainloop-signal.h>
42 #include <polyp/sample.h>
43
44 #if PA_API_VERSION != 8
45 #error Invalid Polypaudio API version
46 #endif
47
48 #define BUFSIZE 1024
49
50 static struct pa_context *context = NULL;
51 static struct pa_mainloop_api *mainloop_api = NULL;
52
53 static char *device = NULL, *sample_name = NULL;
54
55 static SNDFILE *sndfile = NULL;
56 static struct pa_stream *sample_stream = NULL;
57 static struct 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 } action = NONE;
73
74 static void quit(int ret) {
75 assert(mainloop_api);
76 mainloop_api->quit(mainloop_api, ret);
77 }
78
79
80 static void context_drain_complete(struct pa_context *c, void *userdata) {
81 pa_context_disconnect(c);
82 }
83
84 static void drain(void) {
85 struct pa_operation *o;
86 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
87 pa_context_disconnect(context);
88 else
89 pa_operation_unref(o);
90 }
91
92
93 static void complete_action(void) {
94 assert(actions > 0);
95
96 if (!(--actions))
97 drain();
98 }
99
100 static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, void *userdata) {
101 char s[128];
102 if (!i) {
103 fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c)));
104 quit(1);
105 return;
106 }
107
108 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
109 printf("Currently in use: %u blocks containing %s bytes total.\n", i->memblock_total, s);
110
111 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
112 printf("Allocated during whole lifetime: %u blocks containing %s bytes total.\n", i->memblock_allocated, s);
113
114 pa_bytes_snprint(s, sizeof(s), i->scache_size);
115 printf("Sample cache size: %s\n", s);
116
117 complete_action();
118 }
119
120 static void get_server_info_callback(struct pa_context *c, const struct pa_server_info *i, void *useerdata) {
121 char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
122
123 if (!i) {
124 fprintf(stderr, "Failed to get server information: %s\n", pa_strerror(pa_context_errno(c)));
125 quit(1);
126 return;
127 }
128
129 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
130
131 printf("User name: %s\n"
132 "Host Name: %s\n"
133 "Server Name: %s\n"
134 "Server Version: %s\n"
135 "Default Sample Specification: %s\n"
136 "Default Sink: %s\n"
137 "Default Source: %s\n"
138 "Cookie: %08x\n",
139 i->user_name,
140 i->host_name,
141 i->server_name,
142 i->server_version,
143 s,
144 i->default_sink_name,
145 i->default_source_name,
146 i->cookie);
147
148 complete_action();
149 }
150
151 static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata) {
152 char s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5];
153
154 if (is_last < 0) {
155 fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c)));
156 quit(1);
157 return;
158 }
159
160 if (is_last) {
161 complete_action();
162 return;
163 }
164
165 assert(i);
166
167 if (nl)
168 printf("\n");
169 nl = 1;
170
171 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
172
173 printf("*** Sink #%u ***\n"
174 "Name: %s\n"
175 "Type: %s\n"
176 "Description: %s\n"
177 "Sample Specification: %s\n"
178 "Owner Module: %u\n"
179 "Volume: 0x%03x (%0.2f dB)\n"
180 "Monitor Source: %u\n"
181 "Latency: %0.0f usec\n",
182 i->index,
183 i->name,
184 pa_typeid_to_string(i->typeid, tid, sizeof(tid)),
185 i->description,
186 s,
187 i->owner_module,
188 i->volume, pa_volume_to_dB(i->volume),
189 i->monitor_source,
190 (double) i->latency);
191
192 }
193
194 static void get_source_info_callback(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata) {
195 char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], tid[5];
196
197 if (is_last < 0) {
198 fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c)));
199 quit(1);
200 return;
201 }
202
203 if (is_last) {
204 complete_action();
205 return;
206 }
207
208 assert(i);
209
210 if (nl)
211 printf("\n");
212 nl = 1;
213
214 snprintf(t, sizeof(t), "%u", i->monitor_of_sink);
215
216 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
217
218 printf("*** Source #%u ***\n"
219 "Name: %s\n"
220 "Type: %s\n"
221 "Description: %s\n"
222 "Sample Specification: %s\n"
223 "Owner Module: %u\n"
224 "Monitor of Sink: %s\n"
225 "Latency: %0.0f usec\n",
226 i->index,
227 pa_typeid_to_string(i->typeid, tid, sizeof(tid)),
228 i->name,
229 i->description,
230 s,
231 i->owner_module,
232 i->monitor_of_sink != PA_INVALID_INDEX ? t : "no",
233 (double) i->latency);
234
235 }
236
237 static void get_module_info_callback(struct pa_context *c, const struct pa_module_info *i, int is_last, void *userdata) {
238 char t[32];
239
240 if (is_last < 0) {
241 fprintf(stderr, "Failed to get module information: %s\n", pa_strerror(pa_context_errno(c)));
242 quit(1);
243 return;
244 }
245
246 if (is_last) {
247 complete_action();
248 return;
249 }
250
251 assert(i);
252
253 if (nl)
254 printf("\n");
255 nl = 1;
256
257 snprintf(t, sizeof(t), "%u", i->n_used);
258
259 printf("*** Module #%u ***\n"
260 "Name: %s\n"
261 "Argument: %s\n"
262 "Usage counter: %s\n"
263 "Auto unload: %s\n",
264 i->index,
265 i->name,
266 i->argument,
267 i->n_used != PA_INVALID_INDEX ? t : "n/a",
268 i->auto_unload ? "yes" : "no");
269 }
270
271 static void get_client_info_callback(struct pa_context *c, const struct pa_client_info *i, int is_last, void *userdata) {
272 char t[32], tid[5];
273
274 if (is_last < 0) {
275 fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c)));
276 quit(1);
277 return;
278 }
279
280 if (is_last) {
281 complete_action();
282 return;
283 }
284
285 assert(i);
286
287 if (nl)
288 printf("\n");
289 nl = 1;
290
291 snprintf(t, sizeof(t), "%u", i->owner_module);
292
293 printf("*** Client #%u ***\n"
294 "Name: %s\n"
295 "Type: %s\n"
296 "Owner Module: %s\n",
297 i->index,
298 i->name,
299 pa_typeid_to_string(i->typeid, tid, sizeof(tid)),
300 i->owner_module != PA_INVALID_INDEX ? t : "n/a");
301 }
302
303 static void get_sink_input_info_callback(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) {
304 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5];
305
306 if (is_last < 0) {
307 fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c)));
308 quit(1);
309 return;
310 }
311
312 if (is_last) {
313 complete_action();
314 return;
315 }
316
317 assert(i);
318
319 if (nl)
320 printf("\n");
321 nl = 1;
322
323 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
324 snprintf(t, sizeof(t), "%u", i->owner_module);
325 snprintf(k, sizeof(k), "%u", i->client);
326
327 printf("*** Sink Input #%u ***\n"
328 "Name: %s\n"
329 "Type: %s\n"
330 "Owner Module: %s\n"
331 "Client: %s\n"
332 "Sink: %u\n"
333 "Sample Specification: %s\n"
334 "Volume: 0x%03x (%0.2f dB)\n"
335 "Buffer Latency: %0.0f usec\n"
336 "Sink Latency: %0.0f usec\n"
337 "Resample method: %s\n",
338 i->index,
339 i->name,
340 pa_typeid_to_string(i->typeid, tid, sizeof(tid)),
341 i->owner_module != PA_INVALID_INDEX ? t : "n/a",
342 i->client != PA_INVALID_INDEX ? k : "n/a",
343 i->sink,
344 s,
345 i->volume, pa_volume_to_dB(i->volume),
346 (double) i->buffer_usec,
347 (double) i->sink_usec,
348 i->resample_method ? i->resample_method : "n/a");
349 }
350
351
352 static void get_source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata) {
353 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5];
354
355 if (is_last < 0) {
356 fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c)));
357 quit(1);
358 return;
359 }
360
361 if (is_last) {
362 complete_action();
363 return;
364 }
365
366 assert(i);
367
368 if (nl)
369 printf("\n");
370 nl = 1;
371
372 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
373 snprintf(t, sizeof(t), "%u", i->owner_module);
374 snprintf(k, sizeof(k), "%u", i->client);
375
376 printf("*** Source Output #%u ***\n"
377 "Name: %s\n"
378 "Type: %s\n"
379 "Owner Module: %s\n"
380 "Client: %s\n"
381 "Source: %u\n"
382 "Sample Specification: %s\n"
383 "Buffer Latency: %0.0f usec\n"
384 "Source Latency: %0.0f usec\n"
385 "Resample method: %s\n",
386 i->index,
387 i->name,
388 pa_typeid_to_string(i->typeid, tid, sizeof(tid)),
389 i->owner_module != PA_INVALID_INDEX ? t : "n/a",
390 i->client != PA_INVALID_INDEX ? k : "n/a",
391 i->source,
392 s,
393 (double) i->buffer_usec,
394 (double) i->source_usec,
395 i->resample_method ? i->resample_method : "n/a");
396 }
397
398 static void get_sample_info_callback(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata) {
399 char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX];
400
401 if (is_last < 0) {
402 fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c)));
403 quit(1);
404 return;
405 }
406
407 if (is_last) {
408 complete_action();
409 return;
410 }
411
412 assert(i);
413
414 if (nl)
415 printf("\n");
416 nl = 1;
417
418 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
419 pa_bytes_snprint(t, sizeof(t), i->bytes);
420
421 printf("*** Sample #%u ***\n"
422 "Name: %s\n"
423 "Volume: 0x%03x (%0.2f dB)\n"
424 "Sample Specification: %s\n"
425 "Duration: %0.1fs\n"
426 "Size: %s\n"
427 "Lazy: %s\n"
428 "Filename: %s\n",
429 i->index,
430 i->name,
431 i->volume, pa_volume_to_dB(i->volume),
432 pa_sample_spec_valid(&i->sample_spec) ? s : "n/a",
433 (double) i->duration/1000000,
434 t,
435 i->lazy ? "yes" : "no",
436 i->filename ? i->filename : "n/a");
437 }
438
439 static void get_autoload_info_callback(struct pa_context *c, const struct pa_autoload_info *i, int is_last, void *userdata) {
440 if (is_last < 0) {
441 fprintf(stderr, "Failed to get autoload information: %s\n", pa_strerror(pa_context_errno(c)));
442 quit(1);
443 return;
444 }
445
446 if (is_last) {
447 complete_action();
448 return;
449 }
450
451 assert(i);
452
453 if (nl)
454 printf("\n");
455 nl = 1;
456
457 printf("*** Autoload Entry #%u ***\n"
458 "Name: %s\n"
459 "Type: %s\n"
460 "Module: %s\n"
461 "Argument: %s\n",
462 i->index,
463 i->name,
464 i->type == PA_AUTOLOAD_SINK ? "sink" : "source",
465 i->module,
466 i->argument);
467 }
468
469 static void simple_callback(struct pa_context *c, int success, void *userdata) {
470 if (!success) {
471 fprintf(stderr, "Failure: %s\n", pa_strerror(pa_context_errno(c)));
472 quit(1);
473 return;
474 }
475
476 complete_action();
477 }
478
479 static void stream_state_callback(struct pa_stream *s, void *userdata) {
480 assert(s);
481
482 switch (pa_stream_get_state(s)) {
483 case PA_STREAM_CREATING:
484 case PA_STREAM_READY:
485 break;
486
487 case PA_STREAM_TERMINATED:
488 drain();
489 break;
490
491 case PA_STREAM_FAILED:
492 default:
493 fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
494 quit(1);
495 }
496 }
497
498 static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) {
499 sf_count_t l;
500 float *d;
501 assert(s && length && sndfile);
502
503 d = malloc(length);
504 assert(d);
505
506 assert(sample_length >= length);
507 l = length/pa_frame_size(&sample_spec);
508
509 if ((sf_readf_float(sndfile, d, l)) != l) {
510 free(d);
511 fprintf(stderr, "Premature end of file\n");
512 quit(1);
513 }
514
515 pa_stream_write(s, d, length, free, 0);
516
517 sample_length -= length;
518
519 if (sample_length <= 0) {
520 pa_stream_set_write_callback(sample_stream, NULL, NULL);
521 pa_stream_finish_upload(sample_stream);
522 }
523 }
524
525 static void context_state_callback(struct pa_context *c, void *userdata) {
526 assert(c);
527 switch (pa_context_get_state(c)) {
528 case PA_CONTEXT_CONNECTING:
529 case PA_CONTEXT_AUTHORIZING:
530 case PA_CONTEXT_SETTING_NAME:
531 break;
532
533 case PA_CONTEXT_READY:
534 switch (action) {
535 case STAT:
536 actions = 2;
537 pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
538 pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
539 break;
540
541 case PLAY_SAMPLE:
542 pa_operation_unref(pa_context_play_sample(c, sample_name, device, PA_VOLUME_NORM, simple_callback, NULL));
543 break;
544
545 case REMOVE_SAMPLE:
546 pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
547 break;
548
549 case UPLOAD_SAMPLE:
550 sample_stream = pa_stream_new(c, sample_name, &sample_spec);
551 assert(sample_stream);
552
553 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
554 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
555 pa_stream_connect_upload(sample_stream, sample_length);
556 break;
557
558 case EXIT:
559 pa_context_exit_daemon(c);
560 drain();
561
562 case LIST:
563 actions = 8;
564 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
565 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
566 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
567 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
568 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
569 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
570 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
571 pa_operation_unref(pa_context_get_autoload_info_list(c, get_autoload_info_callback, NULL));
572 break;
573
574 default:
575 assert(0);
576 }
577 break;
578
579 case PA_CONTEXT_TERMINATED:
580 quit(0);
581 break;
582
583 case PA_CONTEXT_FAILED:
584 default:
585 fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c)));
586 quit(1);
587 }
588 }
589
590 static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) {
591 fprintf(stderr, "Got SIGINT, exiting.\n");
592 quit(0);
593 }
594
595 static void help(const char *argv0) {
596
597 printf("%s [options] stat\n"
598 "%s [options] list\n"
599 "%s [options] exit\n"
600 "%s [options] upload-sample FILENAME [NAME]\n"
601 "%s [options] play-sample NAME [SINK]\n"
602 "%s [options] remove-sample NAME\n\n"
603 " -h, --help Show this help\n"
604 " --version Show version\n\n"
605 " -s, --server=SERVER The name of the server to connect to\n"
606 " -n, --client-name=NAME How to call this client on the server\n",
607 argv0, argv0, argv0, argv0, argv0, argv0);
608 }
609
610 enum { ARG_VERSION = 256 };
611
612 int main(int argc, char *argv[]) {
613 struct pa_mainloop* m = NULL;
614 char tmp[PATH_MAX];
615 int ret = 1, r, c;
616 char *server = NULL, *client_name = NULL, *bn;
617
618 static const struct option long_options[] = {
619 {"server", 1, NULL, 's'},
620 {"client-name", 1, NULL, 'n'},
621 {"version", 0, NULL, ARG_VERSION},
622 {"help", 0, NULL, 'h'},
623 {NULL, 0, NULL, 0}
624 };
625
626 if (!(bn = strrchr(argv[0], '/')))
627 bn = argv[0];
628 else
629 bn++;
630
631 while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
632 switch (c) {
633 case 'h' :
634 help(bn);
635 ret = 0;
636 goto quit;
637
638 case ARG_VERSION:
639 printf("pactl "PACKAGE_VERSION"\nCompiled with libpolyp %s\nLinked with libpolyp %s\n", pa_get_headers_version(), pa_get_library_version());
640 ret = 0;
641 goto quit;
642
643 case 's':
644 free(server);
645 server = strdup(optarg);
646 break;
647
648 case 'n':
649 free(client_name);
650 client_name = strdup(optarg);
651 break;
652
653 default:
654 goto quit;
655 }
656 }
657
658 if (!client_name)
659 client_name = strdup(bn);
660
661 if (optind < argc) {
662 if (!strcmp(argv[optind], "stat"))
663 action = STAT;
664 else if (!strcmp(argv[optind], "exit"))
665 action = EXIT;
666 else if (!strcmp(argv[optind], "list"))
667 action = LIST;
668 else if (!strcmp(argv[optind], "upload-sample")) {
669 struct SF_INFO sfinfo;
670 action = UPLOAD_SAMPLE;
671
672 if (optind+1 >= argc) {
673 fprintf(stderr, "Please specify a sample file to load\n");
674 goto quit;
675 }
676
677 if (optind+2 < argc)
678 sample_name = strdup(argv[optind+2]);
679 else {
680 char *f = strrchr(argv[optind+1], '/');
681 size_t n;
682 if (f)
683 f++;
684 else
685 f = argv[optind];
686
687 n = strcspn(f, ".");
688 strncpy(tmp, f, n);
689 tmp[n] = 0;
690 sample_name = strdup(tmp);
691 }
692
693 memset(&sfinfo, 0, sizeof(sfinfo));
694 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfinfo))) {
695 fprintf(stderr, "Failed to open sound file.\n");
696 goto quit;
697 }
698
699 sample_spec.format = PA_SAMPLE_FLOAT32;
700 sample_spec.rate = sfinfo.samplerate;
701 sample_spec.channels = sfinfo.channels;
702
703 sample_length = sfinfo.frames*pa_frame_size(&sample_spec);
704 } else if (!strcmp(argv[optind], "play-sample")) {
705 action = PLAY_SAMPLE;
706 if (optind+1 >= argc) {
707 fprintf(stderr, "You have to specify a sample name to play\n");
708 goto quit;
709 }
710
711 sample_name = strdup(argv[optind+1]);
712
713 if (optind+2 < argc)
714 device = strdup(argv[optind+2]);
715
716 } else if (!strcmp(argv[optind], "remove-sample")) {
717 action = REMOVE_SAMPLE;
718 if (optind+1 >= argc) {
719 fprintf(stderr, "You have to specify a sample name to remove\n");
720 goto quit;
721 }
722
723 sample_name = strdup(argv[optind+1]);
724 }
725 }
726
727 if (action == NONE) {
728 fprintf(stderr, "No valid command specified.\n");
729 goto quit;
730 }
731
732 if (!(m = pa_mainloop_new())) {
733 fprintf(stderr, "pa_mainloop_new() failed.\n");
734 goto quit;
735 }
736
737 mainloop_api = pa_mainloop_get_api(m);
738
739 r = pa_signal_init(mainloop_api);
740 assert(r == 0);
741 pa_signal_new(SIGINT, exit_signal_callback, NULL);
742 signal(SIGPIPE, SIG_IGN);
743
744 if (!(context = pa_context_new(mainloop_api, client_name))) {
745 fprintf(stderr, "pa_context_new() failed.\n");
746 goto quit;
747 }
748
749 pa_context_set_state_callback(context, context_state_callback, NULL);
750 pa_context_connect(context, server, 1, NULL);
751
752 if (pa_mainloop_run(m, &ret) < 0) {
753 fprintf(stderr, "pa_mainloop_run() failed.\n");
754 goto quit;
755 }
756
757 quit:
758 if (sample_stream)
759 pa_stream_unref(sample_stream);
760
761 if (context)
762 pa_context_unref(context);
763
764 if (m) {
765 pa_signal_done();
766 pa_mainloop_free(m);
767 }
768
769 if (sndfile)
770 sf_close(sndfile);
771
772 free(server);
773 free(device);
774 free(sample_name);
775
776 return ret;
777 }