]> code.delx.au - pulseaudio/blob - src/utils/pactl.c
Merge branch 'master' of git://0pointer.de/pulseaudio
[pulseaudio] / src / utils / pactl.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
10
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <signal.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <unistd.h>
30 #include <assert.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <limits.h>
34 #include <getopt.h>
35 #include <locale.h>
36
37 #include <sndfile.h>
38
39 #include <pulse/i18n.h>
40 #include <pulse/pulseaudio.h>
41
42 #include <pulsecore/macro.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/sndfile-util.h>
46
47 static pa_context *context = NULL;
48 static pa_mainloop_api *mainloop_api = NULL;
49
50 static char
51 *sample_name = NULL,
52 *sink_name = NULL,
53 *source_name = NULL,
54 *module_name = NULL,
55 *module_args = NULL,
56 *card_name = NULL,
57 *profile_name = NULL,
58 *port_name = NULL;
59
60 static uint32_t
61 sink_input_idx = PA_INVALID_INDEX,
62 source_output_idx = PA_INVALID_INDEX;
63
64 static uint32_t module_index;
65 static pa_bool_t suspend;
66 static pa_bool_t mute;
67 static pa_volume_t volume;
68
69 static pa_proplist *proplist = NULL;
70
71 static SNDFILE *sndfile = NULL;
72 static pa_stream *sample_stream = NULL;
73 static pa_sample_spec sample_spec;
74 static pa_channel_map channel_map;
75 static size_t sample_length = 0;
76 static int actions = 1;
77
78 static pa_bool_t nl = FALSE;
79
80 static enum {
81 NONE,
82 EXIT,
83 STAT,
84 UPLOAD_SAMPLE,
85 PLAY_SAMPLE,
86 REMOVE_SAMPLE,
87 LIST,
88 MOVE_SINK_INPUT,
89 MOVE_SOURCE_OUTPUT,
90 LOAD_MODULE,
91 UNLOAD_MODULE,
92 SUSPEND_SINK,
93 SUSPEND_SOURCE,
94 SET_CARD_PROFILE,
95 SET_SINK_PORT,
96 SET_SOURCE_PORT,
97 SET_SINK_VOLUME,
98 SET_SOURCE_VOLUME,
99 SET_SINK_INPUT_VOLUME,
100 SET_SINK_MUTE,
101 SET_SOURCE_MUTE,
102 SET_SINK_INPUT_MUTE
103 } action = NONE;
104
105 static void quit(int ret) {
106 pa_assert(mainloop_api);
107 mainloop_api->quit(mainloop_api, ret);
108 }
109
110 static void context_drain_complete(pa_context *c, void *userdata) {
111 pa_context_disconnect(c);
112 }
113
114 static void drain(void) {
115 pa_operation *o;
116
117 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
118 pa_context_disconnect(context);
119 else
120 pa_operation_unref(o);
121 }
122
123 static void complete_action(void) {
124 pa_assert(actions > 0);
125
126 if (!(--actions))
127 drain();
128 }
129
130 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
131 char s[PA_BYTES_SNPRINT_MAX];
132 if (!i) {
133 pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c)));
134 quit(1);
135 return;
136 }
137
138 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
139 printf(_("Currently in use: %u blocks containing %s bytes total.\n"), i->memblock_total, s);
140
141 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
142 printf(_("Allocated during whole lifetime: %u blocks containing %s bytes total.\n"), i->memblock_allocated, s);
143
144 pa_bytes_snprint(s, sizeof(s), i->scache_size);
145 printf(_("Sample cache size: %s\n"), s);
146
147 complete_action();
148 }
149
150 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
151 char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
152
153 if (!i) {
154 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
155 quit(1);
156 return;
157 }
158
159 printf(_("Server String: %s\n"
160 "Library Protocol Version: %u\n"
161 "Server Protocol Version: %u\n"
162 "Is Local: %s\n"
163 "Client Index: %u\n"
164 "Tile Size: %zu\n"),
165 pa_context_get_server(c),
166 pa_context_get_protocol_version(c),
167 pa_context_get_server_protocol_version(c),
168 pa_yes_no(pa_context_is_local(c)),
169 pa_context_get_index(c),
170 pa_context_get_tile_size(c, NULL));
171
172 pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
173 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
174
175 printf(_("User Name: %s\n"
176 "Host Name: %s\n"
177 "Server Name: %s\n"
178 "Server Version: %s\n"
179 "Default Sample Specification: %s\n"
180 "Default Channel Map: %s\n"
181 "Default Sink: %s\n"
182 "Default Source: %s\n"
183 "Cookie: %04x:%04x\n"),
184 i->user_name,
185 i->host_name,
186 i->server_name,
187 i->server_version,
188 ss,
189 cm,
190 i->default_sink_name,
191 i->default_source_name,
192 i->cookie >> 16,
193 i->cookie & 0xFFFFU);
194
195 complete_action();
196 }
197
198 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
199
200 static const char *state_table[] = {
201 [1+PA_SINK_INVALID_STATE] = "n/a",
202 [1+PA_SINK_RUNNING] = "RUNNING",
203 [1+PA_SINK_IDLE] = "IDLE",
204 [1+PA_SINK_SUSPENDED] = "SUSPENDED"
205 };
206
207 char
208 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
209 cv[PA_CVOLUME_SNPRINT_MAX],
210 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
211 v[PA_VOLUME_SNPRINT_MAX],
212 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
213 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
214 char *pl;
215
216 if (is_last < 0) {
217 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
218 quit(1);
219 return;
220 }
221
222 if (is_last) {
223 complete_action();
224 return;
225 }
226
227 pa_assert(i);
228
229 if (nl)
230 printf("\n");
231 nl = TRUE;
232
233 printf(_("Sink #%u\n"
234 "\tState: %s\n"
235 "\tName: %s\n"
236 "\tDescription: %s\n"
237 "\tDriver: %s\n"
238 "\tSample Specification: %s\n"
239 "\tChannel Map: %s\n"
240 "\tOwner Module: %u\n"
241 "\tMute: %s\n"
242 "\tVolume: %s%s%s\n"
243 "\t balance %0.2f\n"
244 "\tBase Volume: %s%s%s\n"
245 "\tMonitor Source: %s\n"
246 "\tLatency: %0.0f usec, configured %0.0f usec\n"
247 "\tFlags: %s%s%s%s%s%s\n"
248 "\tProperties:\n\t\t%s\n"),
249 i->index,
250 state_table[1+i->state],
251 i->name,
252 pa_strnull(i->description),
253 pa_strnull(i->driver),
254 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
255 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
256 i->owner_module,
257 pa_yes_no(i->mute),
258 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
259 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
260 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
261 pa_cvolume_get_balance(&i->volume, &i->channel_map),
262 pa_volume_snprint(v, sizeof(v), i->base_volume),
263 i->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
264 i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
265 pa_strnull(i->monitor_source_name),
266 (double) i->latency, (double) i->configured_latency,
267 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
268 i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
269 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
270 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
271 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
272 i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
273 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
274
275 pa_xfree(pl);
276
277 if (i->ports) {
278 pa_sink_port_info **p;
279
280 printf(_("\tPorts:\n"));
281 for (p = i->ports; *p; p++)
282 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
283 }
284
285 if (i->active_port)
286 printf(_("\tActive Port: %s\n"),
287 i->active_port->name);
288 }
289
290 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
291
292 static const char *state_table[] = {
293 [1+PA_SOURCE_INVALID_STATE] = "n/a",
294 [1+PA_SOURCE_RUNNING] = "RUNNING",
295 [1+PA_SOURCE_IDLE] = "IDLE",
296 [1+PA_SOURCE_SUSPENDED] = "SUSPENDED"
297 };
298
299 char
300 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
301 cv[PA_CVOLUME_SNPRINT_MAX],
302 cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
303 v[PA_VOLUME_SNPRINT_MAX],
304 vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
305 cm[PA_CHANNEL_MAP_SNPRINT_MAX];
306 char *pl;
307
308 if (is_last < 0) {
309 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
310 quit(1);
311 return;
312 }
313
314 if (is_last) {
315 complete_action();
316 return;
317 }
318
319 pa_assert(i);
320
321 if (nl)
322 printf("\n");
323 nl = TRUE;
324
325 printf(_("Source #%u\n"
326 "\tState: %s\n"
327 "\tName: %s\n"
328 "\tDescription: %s\n"
329 "\tDriver: %s\n"
330 "\tSample Specification: %s\n"
331 "\tChannel Map: %s\n"
332 "\tOwner Module: %u\n"
333 "\tMute: %s\n"
334 "\tVolume: %s%s%s\n"
335 "\t balance %0.2f\n"
336 "\tBase Volume: %s%s%s\n"
337 "\tMonitor of Sink: %s\n"
338 "\tLatency: %0.0f usec, configured %0.0f usec\n"
339 "\tFlags: %s%s%s%s%s%s\n"
340 "\tProperties:\n\t\t%s\n"),
341 i->index,
342 state_table[1+i->state],
343 i->name,
344 pa_strnull(i->description),
345 pa_strnull(i->driver),
346 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
347 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
348 i->owner_module,
349 pa_yes_no(i->mute),
350 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
351 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
352 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
353 pa_cvolume_get_balance(&i->volume, &i->channel_map),
354 pa_volume_snprint(v, sizeof(v), i->base_volume),
355 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
356 i->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
357 i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
358 (double) i->latency, (double) i->configured_latency,
359 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
360 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
361 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
362 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
363 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
364 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
365 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
366
367 pa_xfree(pl);
368
369 if (i->ports) {
370 pa_source_port_info **p;
371
372 printf(_("\tPorts:\n"));
373 for (p = i->ports; *p; p++)
374 printf("\t\t%s: %s (priority. %u)\n", (*p)->name, (*p)->description, (*p)->priority);
375 }
376
377 if (i->active_port)
378 printf(_("\tActive Port: %s\n"),
379 i->active_port->name);
380 }
381
382 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
383 char t[32];
384 char *pl;
385
386 if (is_last < 0) {
387 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
388 quit(1);
389 return;
390 }
391
392 if (is_last) {
393 complete_action();
394 return;
395 }
396
397 pa_assert(i);
398
399 if (nl)
400 printf("\n");
401 nl = TRUE;
402
403 pa_snprintf(t, sizeof(t), "%u", i->n_used);
404
405 printf(_("Module #%u\n"
406 "\tName: %s\n"
407 "\tArgument: %s\n"
408 "\tUsage counter: %s\n"
409 "\tProperties:\n\t\t%s\n"),
410 i->index,
411 i->name,
412 i->argument ? i->argument : "",
413 i->n_used != PA_INVALID_INDEX ? t : _("n/a"),
414 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
415
416 pa_xfree(pl);
417 }
418
419 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
420 char t[32];
421 char *pl;
422
423 if (is_last < 0) {
424 pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
425 quit(1);
426 return;
427 }
428
429 if (is_last) {
430 complete_action();
431 return;
432 }
433
434 pa_assert(i);
435
436 if (nl)
437 printf("\n");
438 nl = TRUE;
439
440 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
441
442 printf(_("Client #%u\n"
443 "\tDriver: %s\n"
444 "\tOwner Module: %s\n"
445 "\tProperties:\n\t\t%s\n"),
446 i->index,
447 pa_strnull(i->driver),
448 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
449 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
450
451 pa_xfree(pl);
452 }
453
454 static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_last, void *userdata) {
455 char t[32];
456 char *pl;
457
458 if (is_last < 0) {
459 pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c)));
460 complete_action();
461 return;
462 }
463
464 if (is_last) {
465 complete_action();
466 return;
467 }
468
469 pa_assert(i);
470
471 if (nl)
472 printf("\n");
473 nl = TRUE;
474
475 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
476
477 printf(_("Card #%u\n"
478 "\tName: %s\n"
479 "\tDriver: %s\n"
480 "\tOwner Module: %s\n"
481 "\tProperties:\n\t\t%s\n"),
482 i->index,
483 i->name,
484 pa_strnull(i->driver),
485 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
486 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
487
488 if (i->profiles) {
489 pa_card_profile_info *p;
490
491 printf(_("\tProfiles:\n"));
492 for (p = i->profiles; p->name; p++)
493 printf("\t\t%s: %s (sinks: %u, sources: %u, priority. %u)\n", p->name, p->description, p->n_sinks, p->n_sources, p->priority);
494 }
495
496 if (i->active_profile)
497 printf(_("\tActive Profile: %s\n"),
498 i->active_profile->name);
499
500 pa_xfree(pl);
501 }
502
503 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
504 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
505 char *pl;
506
507 if (is_last < 0) {
508 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
509 quit(1);
510 return;
511 }
512
513 if (is_last) {
514 complete_action();
515 return;
516 }
517
518 pa_assert(i);
519
520 if (nl)
521 printf("\n");
522 nl = TRUE;
523
524 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
525 pa_snprintf(k, sizeof(k), "%u", i->client);
526
527 printf(_("Sink Input #%u\n"
528 "\tDriver: %s\n"
529 "\tOwner Module: %s\n"
530 "\tClient: %s\n"
531 "\tSink: %u\n"
532 "\tSample Specification: %s\n"
533 "\tChannel Map: %s\n"
534 "\tMute: %s\n"
535 "\tVolume: %s\n"
536 "\t %s\n"
537 "\t balance %0.2f\n"
538 "\tBuffer Latency: %0.0f usec\n"
539 "\tSink Latency: %0.0f usec\n"
540 "\tResample method: %s\n"
541 "\tProperties:\n\t\t%s\n"),
542 i->index,
543 pa_strnull(i->driver),
544 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
545 i->client != PA_INVALID_INDEX ? k : _("n/a"),
546 i->sink,
547 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
548 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
549 pa_yes_no(i->mute),
550 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
551 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
552 pa_cvolume_get_balance(&i->volume, &i->channel_map),
553 (double) i->buffer_usec,
554 (double) i->sink_usec,
555 i->resample_method ? i->resample_method : _("n/a"),
556 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
557
558 pa_xfree(pl);
559 }
560
561 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
562 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
563 char *pl;
564
565 if (is_last < 0) {
566 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
567 quit(1);
568 return;
569 }
570
571 if (is_last) {
572 complete_action();
573 return;
574 }
575
576 pa_assert(i);
577
578 if (nl)
579 printf("\n");
580 nl = TRUE;
581
582
583 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
584 pa_snprintf(k, sizeof(k), "%u", i->client);
585
586 printf(_("Source Output #%u\n"
587 "\tDriver: %s\n"
588 "\tOwner Module: %s\n"
589 "\tClient: %s\n"
590 "\tSource: %u\n"
591 "\tSample Specification: %s\n"
592 "\tChannel Map: %s\n"
593 "\tBuffer Latency: %0.0f usec\n"
594 "\tSource Latency: %0.0f usec\n"
595 "\tResample method: %s\n"
596 "\tProperties:\n\t\t%s\n"),
597 i->index,
598 pa_strnull(i->driver),
599 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
600 i->client != PA_INVALID_INDEX ? k : _("n/a"),
601 i->source,
602 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
603 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
604 (double) i->buffer_usec,
605 (double) i->source_usec,
606 i->resample_method ? i->resample_method : _("n/a"),
607 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
608
609 pa_xfree(pl);
610 }
611
612 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
613 char t[PA_BYTES_SNPRINT_MAX], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
614 char *pl;
615
616 if (is_last < 0) {
617 pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
618 quit(1);
619 return;
620 }
621
622 if (is_last) {
623 complete_action();
624 return;
625 }
626
627 pa_assert(i);
628
629 if (nl)
630 printf("\n");
631 nl = TRUE;
632
633 pa_bytes_snprint(t, sizeof(t), i->bytes);
634
635 printf(_("Sample #%u\n"
636 "\tName: %s\n"
637 "\tSample Specification: %s\n"
638 "\tChannel Map: %s\n"
639 "\tVolume: %s\n"
640 "\t %s\n"
641 "\t balance %0.2f\n"
642 "\tDuration: %0.1fs\n"
643 "\tSize: %s\n"
644 "\tLazy: %s\n"
645 "\tFilename: %s\n"
646 "\tProperties:\n\t\t%s\n"),
647 i->index,
648 i->name,
649 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
650 pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
651 pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
652 pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume),
653 pa_cvolume_get_balance(&i->volume, &i->channel_map),
654 (double) i->duration/1000000.0,
655 t,
656 pa_yes_no(i->lazy),
657 i->filename ? i->filename : _("n/a"),
658 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
659
660 pa_xfree(pl);
661 }
662
663 static void simple_callback(pa_context *c, int success, void *userdata) {
664 if (!success) {
665 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
666 quit(1);
667 return;
668 }
669
670 complete_action();
671 }
672
673 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
674 if (idx == PA_INVALID_INDEX) {
675 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
676 quit(1);
677 return;
678 }
679
680 printf("%u\n", idx);
681
682 complete_action();
683 }
684
685 static void stream_state_callback(pa_stream *s, void *userdata) {
686 pa_assert(s);
687
688 switch (pa_stream_get_state(s)) {
689 case PA_STREAM_CREATING:
690 case PA_STREAM_READY:
691 break;
692
693 case PA_STREAM_TERMINATED:
694 drain();
695 break;
696
697 case PA_STREAM_FAILED:
698 default:
699 pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
700 quit(1);
701 }
702 }
703
704 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
705 sf_count_t l;
706 float *d;
707 pa_assert(s && length && sndfile);
708
709 d = pa_xmalloc(length);
710
711 pa_assert(sample_length >= length);
712 l = (sf_count_t) (length/pa_frame_size(&sample_spec));
713
714 if ((sf_readf_float(sndfile, d, l)) != l) {
715 pa_xfree(d);
716 pa_log(_("Premature end of file"));
717 quit(1);
718 return;
719 }
720
721 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
722
723 sample_length -= length;
724
725 if (sample_length <= 0) {
726 pa_stream_set_write_callback(sample_stream, NULL, NULL);
727 pa_stream_finish_upload(sample_stream);
728 }
729 }
730
731 static void context_state_callback(pa_context *c, void *userdata) {
732 pa_assert(c);
733 switch (pa_context_get_state(c)) {
734 case PA_CONTEXT_CONNECTING:
735 case PA_CONTEXT_AUTHORIZING:
736 case PA_CONTEXT_SETTING_NAME:
737 break;
738
739 case PA_CONTEXT_READY:
740 switch (action) {
741 case STAT:
742 actions = 2;
743 pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
744 pa_operation_unref(pa_context_get_server_info(c, get_server_info_callback, NULL));
745 break;
746
747 case PLAY_SAMPLE:
748 pa_operation_unref(pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL));
749 break;
750
751 case REMOVE_SAMPLE:
752 pa_operation_unref(pa_context_remove_sample(c, sample_name, simple_callback, NULL));
753 break;
754
755 case UPLOAD_SAMPLE:
756 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
757 pa_assert(sample_stream);
758
759 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
760 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
761 pa_stream_connect_upload(sample_stream, sample_length);
762 break;
763
764 case EXIT:
765 pa_operation_unref(pa_context_exit_daemon(c, simple_callback, NULL));
766 break;
767
768 case LIST:
769 actions = 8;
770 pa_operation_unref(pa_context_get_module_info_list(c, get_module_info_callback, NULL));
771 pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, NULL));
772 pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, NULL));
773 pa_operation_unref(pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL));
774 pa_operation_unref(pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL));
775 pa_operation_unref(pa_context_get_client_info_list(c, get_client_info_callback, NULL));
776 pa_operation_unref(pa_context_get_sample_info_list(c, get_sample_info_callback, NULL));
777 pa_operation_unref(pa_context_get_card_info_list(c, get_card_info_callback, NULL));
778 break;
779
780 case MOVE_SINK_INPUT:
781 pa_operation_unref(pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL));
782 break;
783
784 case MOVE_SOURCE_OUTPUT:
785 pa_operation_unref(pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL));
786 break;
787
788 case LOAD_MODULE:
789 pa_operation_unref(pa_context_load_module(c, module_name, module_args, index_callback, NULL));
790 break;
791
792 case UNLOAD_MODULE:
793 pa_operation_unref(pa_context_unload_module(c, module_index, simple_callback, NULL));
794 break;
795
796 case SUSPEND_SINK:
797 if (sink_name)
798 pa_operation_unref(pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL));
799 else
800 pa_operation_unref(pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
801 break;
802
803 case SUSPEND_SOURCE:
804 if (source_name)
805 pa_operation_unref(pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL));
806 else
807 pa_operation_unref(pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL));
808 break;
809
810 case SET_CARD_PROFILE:
811 pa_operation_unref(pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL));
812 break;
813
814 case SET_SINK_PORT:
815 pa_operation_unref(pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL));
816 break;
817
818 case SET_SOURCE_PORT:
819 pa_operation_unref(pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL));
820 break;
821
822 case SET_SINK_MUTE:
823 pa_operation_unref(pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL));
824 break;
825
826 case SET_SOURCE_MUTE:
827 pa_operation_unref(pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL));
828 break;
829
830 case SET_SINK_INPUT_MUTE:
831 pa_operation_unref(pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL));
832 break;
833
834 case SET_SINK_VOLUME: {
835 pa_cvolume v;
836
837 pa_cvolume_set(&v, 1, volume);
838 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
839 break;
840 }
841
842 case SET_SOURCE_VOLUME: {
843 pa_cvolume v;
844
845 pa_cvolume_set(&v, 1, volume);
846 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
847 break;
848 }
849
850 case SET_SINK_INPUT_VOLUME: {
851 pa_cvolume v;
852
853 pa_cvolume_set(&v, 1, volume);
854 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
855 break;
856 }
857
858 default:
859 pa_assert_not_reached();
860 }
861 break;
862
863 case PA_CONTEXT_TERMINATED:
864 quit(0);
865 break;
866
867 case PA_CONTEXT_FAILED:
868 default:
869 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
870 quit(1);
871 }
872 }
873
874 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
875 pa_log(_("Got SIGINT, exiting."));
876 quit(0);
877 }
878
879 static void help(const char *argv0) {
880
881 printf(_("%s [options] stat\n"
882 "%s [options] list\n"
883 "%s [options] exit\n"
884 "%s [options] upload-sample FILENAME [NAME]\n"
885 "%s [options] play-sample NAME [SINK]\n"
886 "%s [options] remove-sample NAME\n"
887 "%s [options] move-sink-input SINKINPUT SINK\n"
888 "%s [options] move-source-output SOURCEOUTPUT SOURCE\n"
889 "%s [options] load-module NAME [ARGS ...]\n"
890 "%s [options] unload-module MODULE\n"
891 "%s [options] suspend-sink SINK 1|0\n"
892 "%s [options] suspend-source SOURCE 1|0\n"
893 "%s [options] set-card-profile CARD PROFILE\n"
894 "%s [options] set-sink-port SINK PORT\n"
895 "%s [options] set-source-port SOURCE PORT\n"
896 "%s [options] set-sink-volume SINK VOLUME\n"
897 "%s [options] set-source-volume SOURCE VOLUME\n"
898 "%s [options] set-sink-input-volume SINKINPUT VOLUME\n"
899 "%s [options] set-sink-mute SINK 1|0\n"
900 "%s [options] set-source-mute SOURCE 1|0\n"
901 "%s [options] set-sink-input-mute SINKINPUT 1|0\n\n"
902 " -h, --help Show this help\n"
903 " --version Show version\n\n"
904 " -s, --server=SERVER The name of the server to connect to\n"
905 " -n, --client-name=NAME How to call this client on the server\n"),
906 argv0, argv0, argv0, argv0, argv0,
907 argv0, argv0, argv0, argv0, argv0,
908 argv0, argv0, argv0, argv0, argv0,
909 argv0, argv0, argv0, argv0, argv0,
910 argv0);
911 }
912
913 enum {
914 ARG_VERSION = 256
915 };
916
917 int main(int argc, char *argv[]) {
918 pa_mainloop* m = NULL;
919 int ret = 1, c;
920 char *server = NULL, *bn;
921
922 static const struct option long_options[] = {
923 {"server", 1, NULL, 's'},
924 {"client-name", 1, NULL, 'n'},
925 {"version", 0, NULL, ARG_VERSION},
926 {"help", 0, NULL, 'h'},
927 {NULL, 0, NULL, 0}
928 };
929
930 setlocale(LC_ALL, "");
931 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
932
933 bn = pa_path_get_filename(argv[0]);
934
935 proplist = pa_proplist_new();
936
937 while ((c = getopt_long(argc, argv, "s:n:h", long_options, NULL)) != -1) {
938 switch (c) {
939 case 'h' :
940 help(bn);
941 ret = 0;
942 goto quit;
943
944 case ARG_VERSION:
945 printf(_("pactl %s\n"
946 "Compiled with libpulse %s\n"
947 "Linked with libpulse %s\n"),
948 PACKAGE_VERSION,
949 pa_get_headers_version(),
950 pa_get_library_version());
951 ret = 0;
952 goto quit;
953
954 case 's':
955 pa_xfree(server);
956 server = pa_xstrdup(optarg);
957 break;
958
959 case 'n': {
960 char *t;
961
962 if (!(t = pa_locale_to_utf8(optarg)) ||
963 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
964
965 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
966 pa_xfree(t);
967 goto quit;
968 }
969
970 pa_xfree(t);
971 break;
972 }
973
974 default:
975 goto quit;
976 }
977 }
978
979 if (optind < argc) {
980 if (pa_streq(argv[optind], "stat"))
981 action = STAT;
982 else if (pa_streq(argv[optind], "exit"))
983 action = EXIT;
984 else if (pa_streq(argv[optind], "list"))
985 action = LIST;
986 else if (pa_streq(argv[optind], "upload-sample")) {
987 struct SF_INFO sfi;
988 action = UPLOAD_SAMPLE;
989
990 if (optind+1 >= argc) {
991 pa_log(_("Please specify a sample file to load"));
992 goto quit;
993 }
994
995 if (optind+2 < argc)
996 sample_name = pa_xstrdup(argv[optind+2]);
997 else {
998 char *f = pa_path_get_filename(argv[optind+1]);
999 sample_name = pa_xstrndup(f, strcspn(f, "."));
1000 }
1001
1002 pa_zero(sfi);
1003 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
1004 pa_log(_("Failed to open sound file."));
1005 goto quit;
1006 }
1007
1008 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1009 pa_log(_("Failed to determine sample specification from file."));
1010 goto quit;
1011 }
1012 sample_spec.format = PA_SAMPLE_FLOAT32;
1013
1014 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1015 if (sample_spec.channels > 2)
1016 pa_log(_("Warning: Failed to determine sample specification from file."));
1017 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1018 }
1019
1020 pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
1021 sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
1022
1023 } else if (pa_streq(argv[optind], "play-sample")) {
1024 action = PLAY_SAMPLE;
1025 if (argc != optind+2 && argc != optind+3) {
1026 pa_log(_("You have to specify a sample name to play"));
1027 goto quit;
1028 }
1029
1030 sample_name = pa_xstrdup(argv[optind+1]);
1031
1032 if (optind+2 < argc)
1033 sink_name = pa_xstrdup(argv[optind+2]);
1034
1035 } else if (pa_streq(argv[optind], "remove-sample")) {
1036 action = REMOVE_SAMPLE;
1037 if (argc != optind+2) {
1038 pa_log(_("You have to specify a sample name to remove"));
1039 goto quit;
1040 }
1041
1042 sample_name = pa_xstrdup(argv[optind+1]);
1043
1044 } else if (pa_streq(argv[optind], "move-sink-input")) {
1045 action = MOVE_SINK_INPUT;
1046 if (argc != optind+3) {
1047 pa_log(_("You have to specify a sink input index and a sink"));
1048 goto quit;
1049 }
1050
1051 sink_input_idx = (uint32_t) atoi(argv[optind+1]);
1052 sink_name = pa_xstrdup(argv[optind+2]);
1053
1054 } else if (pa_streq(argv[optind], "move-source-output")) {
1055 action = MOVE_SOURCE_OUTPUT;
1056 if (argc != optind+3) {
1057 pa_log(_("You have to specify a source output index and a source"));
1058 goto quit;
1059 }
1060
1061 source_output_idx = (uint32_t) atoi(argv[optind+1]);
1062 source_name = pa_xstrdup(argv[optind+2]);
1063
1064 } else if (pa_streq(argv[optind], "load-module")) {
1065 int i;
1066 size_t n = 0;
1067 char *p;
1068
1069 action = LOAD_MODULE;
1070
1071 if (argc <= optind+1) {
1072 pa_log(_("You have to specify a module name and arguments."));
1073 goto quit;
1074 }
1075
1076 module_name = argv[optind+1];
1077
1078 for (i = optind+2; i < argc; i++)
1079 n += strlen(argv[i])+1;
1080
1081 if (n > 0) {
1082 p = module_args = pa_xmalloc(n);
1083
1084 for (i = optind+2; i < argc; i++)
1085 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
1086 }
1087
1088 } else if (pa_streq(argv[optind], "unload-module")) {
1089 action = UNLOAD_MODULE;
1090
1091 if (argc != optind+2) {
1092 pa_log(_("You have to specify a module index"));
1093 goto quit;
1094 }
1095
1096 module_index = (uint32_t) atoi(argv[optind+1]);
1097
1098 } else if (pa_streq(argv[optind], "suspend-sink")) {
1099 action = SUSPEND_SINK;
1100
1101 if (argc > optind+3 || optind+1 >= argc) {
1102 pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
1103 goto quit;
1104 }
1105
1106 suspend = pa_parse_boolean(argv[argc-1]);
1107
1108 if (argc > optind+2)
1109 sink_name = pa_xstrdup(argv[optind+1]);
1110
1111 } else if (pa_streq(argv[optind], "suspend-source")) {
1112 action = SUSPEND_SOURCE;
1113
1114 if (argc > optind+3 || optind+1 >= argc) {
1115 pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
1116 goto quit;
1117 }
1118
1119 suspend = pa_parse_boolean(argv[argc-1]);
1120
1121 if (argc > optind+2)
1122 source_name = pa_xstrdup(argv[optind+1]);
1123 } else if (pa_streq(argv[optind], "set-card-profile")) {
1124 action = SET_CARD_PROFILE;
1125
1126 if (argc != optind+3) {
1127 pa_log(_("You have to specify a card name/index and a profile name"));
1128 goto quit;
1129 }
1130
1131 card_name = pa_xstrdup(argv[optind+1]);
1132 profile_name = pa_xstrdup(argv[optind+2]);
1133
1134 } else if (pa_streq(argv[optind], "set-sink-port")) {
1135 action = SET_SINK_PORT;
1136
1137 if (argc != optind+3) {
1138 pa_log(_("You have to specify a sink name/index and a port name"));
1139 goto quit;
1140 }
1141
1142 sink_name = pa_xstrdup(argv[optind+1]);
1143 port_name = pa_xstrdup(argv[optind+2]);
1144
1145 } else if (pa_streq(argv[optind], "set-source-port")) {
1146 action = SET_SOURCE_PORT;
1147
1148 if (argc != optind+3) {
1149 pa_log(_("You have to specify a source name/index and a port name"));
1150 goto quit;
1151 }
1152
1153 source_name = pa_xstrdup(argv[optind+1]);
1154 port_name = pa_xstrdup(argv[optind+2]);
1155
1156 } else if (pa_streq(argv[optind], "set-sink-volume")) {
1157 uint32_t v;
1158 action = SET_SINK_VOLUME;
1159
1160 if (argc != optind+3) {
1161 pa_log(_("You have to specify a sink name/index and a volume"));
1162 goto quit;
1163 }
1164
1165 if (pa_atou(argv[optind+2], &v) < 0) {
1166 pa_log(_("Invalid volume specification"));
1167 goto quit;
1168 }
1169
1170 sink_name = pa_xstrdup(argv[optind+1]);
1171 volume = (pa_volume_t) v;
1172
1173 } else if (pa_streq(argv[optind], "set-source-volume")) {
1174 uint32_t v;
1175 action = SET_SOURCE_VOLUME;
1176
1177 if (argc != optind+3) {
1178 pa_log(_("You have to specify a source name/index and a volume"));
1179 goto quit;
1180 }
1181
1182 if (pa_atou(argv[optind+2], &v) < 0) {
1183 pa_log(_("Invalid volume specification"));
1184 goto quit;
1185 }
1186
1187 source_name = pa_xstrdup(argv[optind+1]);
1188 volume = (pa_volume_t) v;
1189
1190 } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
1191 uint32_t v;
1192 action = SET_SINK_INPUT_VOLUME;
1193
1194 if (argc != optind+3) {
1195 pa_log(_("You have to specify a sink input index and a volume"));
1196 goto quit;
1197 }
1198
1199 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1200 pa_log(_("Invalid sink input index"));
1201 goto quit;
1202 }
1203
1204 if (pa_atou(argv[optind+2], &v) < 0) {
1205 pa_log(_("Invalid volume specification"));
1206 goto quit;
1207 }
1208
1209 volume = (pa_volume_t) v;
1210
1211 } else if (pa_streq(argv[optind], "set-sink-mute")) {
1212 int b;
1213 action = SET_SINK_MUTE;
1214
1215 if (argc != optind+3) {
1216 pa_log(_("You have to specify a sink name/index and a mute boolean"));
1217 goto quit;
1218 }
1219
1220 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1221 pa_log(_("Invalid volume specification"));
1222 goto quit;
1223 }
1224
1225 sink_name = pa_xstrdup(argv[optind+1]);
1226 mute = b;
1227
1228 } else if (pa_streq(argv[optind], "set-source-mute")) {
1229 int b;
1230 action = SET_SOURCE_MUTE;
1231
1232 if (argc != optind+3) {
1233 pa_log(_("You have to specify a source name/index and a mute boolean"));
1234 goto quit;
1235 }
1236
1237 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1238 pa_log(_("Invalid volume specification"));
1239 goto quit;
1240 }
1241
1242 source_name = pa_xstrdup(argv[optind+1]);
1243 mute = b;
1244
1245 } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
1246 int b;
1247 action = SET_SINK_INPUT_MUTE;
1248
1249 if (argc != optind+3) {
1250 pa_log(_("You have to specify a sink input index and a mute boolean"));
1251 goto quit;
1252 }
1253
1254 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1255 pa_log(_("Invalid sink input index specification"));
1256 goto quit;
1257 }
1258
1259 if ((b = pa_parse_boolean(argv[optind+2])) < 0) {
1260 pa_log(_("Invalid volume specification"));
1261 goto quit;
1262 }
1263
1264 mute = b;
1265
1266 } else if (pa_streq(argv[optind], "help")) {
1267 help(bn);
1268 ret = 0;
1269 goto quit;
1270 }
1271 }
1272
1273 if (action == NONE) {
1274 pa_log(_("No valid command specified."));
1275 goto quit;
1276 }
1277
1278 if (!(m = pa_mainloop_new())) {
1279 pa_log(_("pa_mainloop_new() failed."));
1280 goto quit;
1281 }
1282
1283 mainloop_api = pa_mainloop_get_api(m);
1284
1285 pa_assert_se(pa_signal_init(mainloop_api) == 0);
1286 pa_signal_new(SIGINT, exit_signal_callback, NULL);
1287 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
1288 pa_disable_sigpipe();
1289
1290 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
1291 pa_log(_("pa_context_new() failed."));
1292 goto quit;
1293 }
1294
1295 pa_context_set_state_callback(context, context_state_callback, NULL);
1296 if (pa_context_connect(context, server, 0, NULL) < 0) {
1297 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
1298 goto quit;
1299 }
1300
1301 if (pa_mainloop_run(m, &ret) < 0) {
1302 pa_log(_("pa_mainloop_run() failed."));
1303 goto quit;
1304 }
1305
1306 quit:
1307 if (sample_stream)
1308 pa_stream_unref(sample_stream);
1309
1310 if (context)
1311 pa_context_unref(context);
1312
1313 if (m) {
1314 pa_signal_done();
1315 pa_mainloop_free(m);
1316 }
1317
1318 pa_xfree(server);
1319 pa_xfree(sample_name);
1320 pa_xfree(sink_name);
1321 pa_xfree(source_name);
1322 pa_xfree(module_args);
1323 pa_xfree(card_name);
1324 pa_xfree(profile_name);
1325
1326 if (sndfile)
1327 sf_close(sndfile);
1328
1329 if (proplist)
1330 pa_proplist_free(proplist);
1331
1332 return ret;
1333 }