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