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