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, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <signal.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <getopt.h>
32 #include <locale.h>
33 #include <ctype.h>
34
35 #include <sndfile.h>
36
37 #include <pulse/pulseaudio.h>
38 #include <pulse/ext-device-restore.h>
39
40 #include <pulsecore/i18n.h>
41 #include <pulsecore/macro.h>
42 #include <pulsecore/core-util.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/sndfile-util.h>
45
46 static pa_context *context = NULL;
47 static pa_mainloop_api *mainloop_api = NULL;
48
49 static char
50 *list_type = NULL,
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 *formats = NULL;
60
61 static uint32_t
62 sink_input_idx = PA_INVALID_INDEX,
63 source_output_idx = PA_INVALID_INDEX,
64 sink_idx = PA_INVALID_INDEX;
65
66 static bool short_list_format = false;
67 static uint32_t module_index;
68 static int32_t latency_offset;
69 static bool suspend;
70 static pa_cvolume volume;
71 static enum volume_flags {
72 VOL_UINT = 0,
73 VOL_PERCENT = 1,
74 VOL_LINEAR = 2,
75 VOL_DECIBEL = 3,
76 VOL_ABSOLUTE = 0 << 4,
77 VOL_RELATIVE = 1 << 4,
78 } volume_flags;
79
80 static enum mute_flags {
81 INVALID_MUTE = -1,
82 UNMUTE = 0,
83 MUTE = 1,
84 TOGGLE_MUTE = 2
85 } mute = INVALID_MUTE;
86
87 static pa_proplist *proplist = NULL;
88
89 static SNDFILE *sndfile = NULL;
90 static pa_stream *sample_stream = NULL;
91 static pa_sample_spec sample_spec;
92 static pa_channel_map channel_map;
93 static size_t sample_length = 0;
94
95 /* This variable tracks the number of ongoing asynchronous operations. When a
96 * new operation begins, this is incremented simply with actions++, and when
97 * an operation finishes, this is decremented with the complete_action()
98 * function, which shuts down the program if actions reaches zero. */
99 static int actions = 0;
100
101 static bool nl = false;
102
103 static enum {
104 NONE,
105 EXIT,
106 STAT,
107 INFO,
108 UPLOAD_SAMPLE,
109 PLAY_SAMPLE,
110 REMOVE_SAMPLE,
111 LIST,
112 MOVE_SINK_INPUT,
113 MOVE_SOURCE_OUTPUT,
114 LOAD_MODULE,
115 UNLOAD_MODULE,
116 SUSPEND_SINK,
117 SUSPEND_SOURCE,
118 SET_CARD_PROFILE,
119 SET_SINK_PORT,
120 SET_DEFAULT_SINK,
121 SET_SOURCE_PORT,
122 SET_DEFAULT_SOURCE,
123 SET_SINK_VOLUME,
124 SET_SOURCE_VOLUME,
125 SET_SINK_INPUT_VOLUME,
126 SET_SOURCE_OUTPUT_VOLUME,
127 SET_SINK_MUTE,
128 SET_SOURCE_MUTE,
129 SET_SINK_INPUT_MUTE,
130 SET_SOURCE_OUTPUT_MUTE,
131 SET_SINK_FORMATS,
132 SET_PORT_LATENCY_OFFSET,
133 SUBSCRIBE
134 } action = NONE;
135
quit(int ret)136 static void quit(int ret) {
137 pa_assert(mainloop_api);
138 mainloop_api->quit(mainloop_api, ret);
139 }
140
context_drain_complete(pa_context * c,void * userdata)141 static void context_drain_complete(pa_context *c, void *userdata) {
142 pa_context_disconnect(c);
143 }
144
drain(void)145 static void drain(void) {
146 pa_operation *o;
147
148 if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
149 pa_context_disconnect(context);
150 else
151 pa_operation_unref(o);
152 }
153
complete_action(void)154 static void complete_action(void) {
155 pa_assert(actions > 0);
156
157 if (!(--actions))
158 drain();
159 }
160
stat_callback(pa_context * c,const pa_stat_info * i,void * userdata)161 static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) {
162 char s[PA_BYTES_SNPRINT_MAX];
163 if (!i) {
164 pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c)));
165 quit(1);
166 return;
167 }
168
169 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size);
170 printf(ngettext("Currently in use: %u block containing %s bytes total.\n",
171 "Currently in use: %u blocks containing %s bytes total.\n",
172 i->memblock_total),
173 i->memblock_total, s);
174
175 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size);
176 printf(ngettext("Allocated during whole lifetime: %u block containing %s bytes total.\n",
177 "Allocated during whole lifetime: %u blocks containing %s bytes total.\n",
178 i->memblock_allocated),
179 i->memblock_allocated, s);
180
181 pa_bytes_snprint(s, sizeof(s), i->scache_size);
182 printf(_("Sample cache size: %s\n"), s);
183
184 complete_action();
185 }
186
get_server_info_callback(pa_context * c,const pa_server_info * i,void * useerdata)187 static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) {
188 char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
189
190 if (!i) {
191 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c)));
192 quit(1);
193 return;
194 }
195
196 printf(_("Server String: %s\n"
197 "Library Protocol Version: %u\n"
198 "Server Protocol Version: %u\n"
199 "Is Local: %s\n"
200 "Client Index: %u\n"
201 "Tile Size: %zu\n"),
202 pa_context_get_server(c),
203 pa_context_get_protocol_version(c),
204 pa_context_get_server_protocol_version(c),
205 pa_yes_no_localised(pa_context_is_local(c)),
206 pa_context_get_index(c),
207 pa_context_get_tile_size(c, NULL));
208
209 pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
210 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map);
211
212 printf(_("User Name: %s\n"
213 "Host Name: %s\n"
214 "Server Name: %s\n"
215 "Server Version: %s\n"
216 "Default Sample Specification: %s\n"
217 "Default Channel Map: %s\n"
218 "Default Sink: %s\n"
219 "Default Source: %s\n"
220 "Cookie: %04x:%04x\n"),
221 i->user_name,
222 i->host_name,
223 i->server_name,
224 i->server_version,
225 ss,
226 cm,
227 i->default_sink_name,
228 i->default_source_name,
229 i->cookie >> 16,
230 i->cookie & 0xFFFFU);
231
232 complete_action();
233 }
234
get_available_str(int available)235 static const char* get_available_str(int available) {
236 switch (available) {
237 case PA_PORT_AVAILABLE_UNKNOWN: return _("availability unknown");
238 case PA_PORT_AVAILABLE_YES: return _("available");
239 case PA_PORT_AVAILABLE_NO: return _("not available");
240 }
241
242 pa_assert_not_reached();
243 }
244
get_device_port_type(unsigned int type)245 static const char* get_device_port_type(unsigned int type) {
246 static char buf[32];
247 switch (type) {
248 case PA_DEVICE_PORT_TYPE_UNKNOWN: return _("Unknown");
249 case PA_DEVICE_PORT_TYPE_AUX: return _("Aux");
250 case PA_DEVICE_PORT_TYPE_SPEAKER: return _("Speaker");
251 case PA_DEVICE_PORT_TYPE_HEADPHONES: return _("Headphones");
252 case PA_DEVICE_PORT_TYPE_LINE: return _("Line");
253 case PA_DEVICE_PORT_TYPE_MIC: return _("Mic");
254 case PA_DEVICE_PORT_TYPE_HEADSET: return _("Headset");
255 case PA_DEVICE_PORT_TYPE_HANDSET: return _("Handset");
256 case PA_DEVICE_PORT_TYPE_EARPIECE: return _("Earpiece");
257 case PA_DEVICE_PORT_TYPE_SPDIF: return _("SPDIF");
258 case PA_DEVICE_PORT_TYPE_HDMI: return _("HDMI");
259 case PA_DEVICE_PORT_TYPE_TV: return _("TV");
260 case PA_DEVICE_PORT_TYPE_RADIO: return _("Radio");
261 case PA_DEVICE_PORT_TYPE_VIDEO: return _("Video");
262 case PA_DEVICE_PORT_TYPE_USB: return _("USB");
263 case PA_DEVICE_PORT_TYPE_BLUETOOTH: return _("Bluetooth");
264 case PA_DEVICE_PORT_TYPE_PORTABLE: return _("Portable");
265 case PA_DEVICE_PORT_TYPE_HANDSFREE: return _("Handsfree");
266 case PA_DEVICE_PORT_TYPE_CAR: return _("Car");
267 case PA_DEVICE_PORT_TYPE_HIFI: return _("HiFi");
268 case PA_DEVICE_PORT_TYPE_PHONE: return _("Phone");
269 case PA_DEVICE_PORT_TYPE_NETWORK: return _("Network");
270 case PA_DEVICE_PORT_TYPE_ANALOG: return _("Analog");
271 }
272 snprintf(buf, sizeof(buf), "%s-%u", _("Unknown"), type);
273 return buf;
274 }
275
get_sink_info_callback(pa_context * c,const pa_sink_info * i,int is_last,void * userdata)276 static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
277
278 static const char *state_table[] = {
279 [1+PA_SINK_INVALID_STATE] = "n/a",
280 [1+PA_SINK_RUNNING] = "RUNNING",
281 [1+PA_SINK_IDLE] = "IDLE",
282 [1+PA_SINK_SUSPENDED] = "SUSPENDED"
283 };
284
285 char
286 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
287 cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
288 v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
289 cm[PA_CHANNEL_MAP_SNPRINT_MAX],
290 f[PA_FORMAT_INFO_SNPRINT_MAX];
291 char *pl;
292
293 if (is_last < 0) {
294 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
295 quit(1);
296 return;
297 }
298
299 if (is_last) {
300 complete_action();
301 return;
302 }
303
304 pa_assert(i);
305
306 if (nl && !short_list_format)
307 printf("\n");
308 nl = true;
309
310 if (short_list_format) {
311 printf("%u\t%s\t%s\t%s\t%s\n",
312 i->index,
313 i->name,
314 pa_strnull(i->driver),
315 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
316 state_table[1+i->state]);
317 return;
318 }
319
320 printf(_("Sink #%u\n"
321 "\tState: %s\n"
322 "\tName: %s\n"
323 "\tDescription: %s\n"
324 "\tDriver: %s\n"
325 "\tSample Specification: %s\n"
326 "\tChannel Map: %s\n"
327 "\tOwner Module: %u\n"
328 "\tMute: %s\n"
329 "\tVolume: %s\n"
330 "\t balance %0.2f\n"
331 "\tBase Volume: %s\n"
332 "\tMonitor Source: %s\n"
333 "\tLatency: %0.0f usec, configured %0.0f usec\n"
334 "\tFlags: %s%s%s%s%s%s%s\n"
335 "\tProperties:\n\t\t%s\n"),
336 i->index,
337 state_table[1+i->state],
338 i->name,
339 pa_strnull(i->description),
340 pa_strnull(i->driver),
341 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
342 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
343 i->owner_module,
344 pa_yes_no_localised(i->mute),
345 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SINK_DECIBEL_VOLUME),
346 pa_cvolume_get_balance(&i->volume, &i->channel_map),
347 pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SINK_DECIBEL_VOLUME),
348 pa_strnull(i->monitor_source_name),
349 (double) i->latency, (double) i->configured_latency,
350 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
351 i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
352 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
353 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
354 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
355 i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
356 i->flags & PA_SINK_SET_FORMATS ? "SET_FORMATS " : "",
357 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
358
359 pa_xfree(pl);
360
361 if (i->ports) {
362 pa_sink_port_info **p;
363
364 printf(_("\tPorts:\n"));
365 for (p = i->ports; *p; p++)
366 printf(_("\t\t%s: %s (type: %s, priority: %u%s%s, %s)\n"),
367 (*p)->name, (*p)->description, get_device_port_type((*p)->type),
368 (*p)->priority, (*p)->availability_group ? _(", availability group: ") : "",
369 (*p)->availability_group ?: "", get_available_str((*p)->available));
370 }
371
372 if (i->active_port)
373 printf(_("\tActive Port: %s\n"),
374 i->active_port->name);
375
376 if (i->formats) {
377 uint8_t j;
378
379 printf(_("\tFormats:\n"));
380 for (j = 0; j < i->n_formats; j++)
381 printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j]));
382 }
383 }
384
get_source_info_callback(pa_context * c,const pa_source_info * i,int is_last,void * userdata)385 static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
386
387 static const char *state_table[] = {
388 [1+PA_SOURCE_INVALID_STATE] = "n/a",
389 [1+PA_SOURCE_RUNNING] = "RUNNING",
390 [1+PA_SOURCE_IDLE] = "IDLE",
391 [1+PA_SOURCE_SUSPENDED] = "SUSPENDED"
392 };
393
394 char
395 s[PA_SAMPLE_SPEC_SNPRINT_MAX],
396 cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
397 v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
398 cm[PA_CHANNEL_MAP_SNPRINT_MAX],
399 f[PA_FORMAT_INFO_SNPRINT_MAX];
400 char *pl;
401
402 if (is_last < 0) {
403 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
404 quit(1);
405 return;
406 }
407
408 if (is_last) {
409 complete_action();
410 return;
411 }
412
413 pa_assert(i);
414
415 if (nl && !short_list_format)
416 printf("\n");
417 nl = true;
418
419 if (short_list_format) {
420 printf("%u\t%s\t%s\t%s\t%s\n",
421 i->index,
422 i->name,
423 pa_strnull(i->driver),
424 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
425 state_table[1+i->state]);
426 return;
427 }
428
429 printf(_("Source #%u\n"
430 "\tState: %s\n"
431 "\tName: %s\n"
432 "\tDescription: %s\n"
433 "\tDriver: %s\n"
434 "\tSample Specification: %s\n"
435 "\tChannel Map: %s\n"
436 "\tOwner Module: %u\n"
437 "\tMute: %s\n"
438 "\tVolume: %s\n"
439 "\t balance %0.2f\n"
440 "\tBase Volume: %s\n"
441 "\tMonitor of Sink: %s\n"
442 "\tLatency: %0.0f usec, configured %0.0f usec\n"
443 "\tFlags: %s%s%s%s%s%s\n"
444 "\tProperties:\n\t\t%s\n"),
445 i->index,
446 state_table[1+i->state],
447 i->name,
448 pa_strnull(i->description),
449 pa_strnull(i->driver),
450 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
451 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
452 i->owner_module,
453 pa_yes_no_localised(i->mute),
454 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SOURCE_DECIBEL_VOLUME),
455 pa_cvolume_get_balance(&i->volume, &i->channel_map),
456 pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SOURCE_DECIBEL_VOLUME),
457 i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"),
458 (double) i->latency, (double) i->configured_latency,
459 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
460 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
461 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
462 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
463 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
464 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
465 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
466
467 pa_xfree(pl);
468
469 if (i->ports) {
470 pa_source_port_info **p;
471
472 printf(_("\tPorts:\n"));
473 for (p = i->ports; *p; p++)
474 printf(_("\t\t%s: %s (type: %s, priority: %u%s%s, %s)\n"),
475 (*p)->name, (*p)->description, get_device_port_type((*p)->type),
476 (*p)->priority, (*p)->availability_group ? _(", availability group: ") : "",
477 (*p)->availability_group ?: "", get_available_str((*p)->available));
478 }
479
480 if (i->active_port)
481 printf(_("\tActive Port: %s\n"),
482 i->active_port->name);
483
484 if (i->formats) {
485 uint8_t j;
486
487 printf(_("\tFormats:\n"));
488 for (j = 0; j < i->n_formats; j++)
489 printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j]));
490 }
491 }
492
get_module_info_callback(pa_context * c,const pa_module_info * i,int is_last,void * userdata)493 static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
494 char t[32];
495 char *pl;
496
497 if (is_last < 0) {
498 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
499 quit(1);
500 return;
501 }
502
503 if (is_last) {
504 complete_action();
505 return;
506 }
507
508 pa_assert(i);
509
510 if (nl && !short_list_format)
511 printf("\n");
512 nl = true;
513
514 pa_snprintf(t, sizeof(t), "%u", i->n_used);
515
516 if (short_list_format) {
517 printf("%u\t%s\t%s\t\n", i->index, i->name, i->argument ? i->argument : "");
518 return;
519 }
520
521 printf(_("Module #%u\n"
522 "\tName: %s\n"
523 "\tArgument: %s\n"
524 "\tUsage counter: %s\n"
525 "\tProperties:\n\t\t%s\n"),
526 i->index,
527 i->name,
528 i->argument ? i->argument : "",
529 i->n_used != PA_INVALID_INDEX ? t : _("n/a"),
530 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
531
532 pa_xfree(pl);
533 }
534
get_client_info_callback(pa_context * c,const pa_client_info * i,int is_last,void * userdata)535 static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) {
536 char t[32];
537 char *pl;
538
539 if (is_last < 0) {
540 pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c)));
541 quit(1);
542 return;
543 }
544
545 if (is_last) {
546 complete_action();
547 return;
548 }
549
550 pa_assert(i);
551
552 if (nl && !short_list_format)
553 printf("\n");
554 nl = true;
555
556 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
557
558 if (short_list_format) {
559 printf("%u\t%s\t%s\n",
560 i->index,
561 pa_strnull(i->driver),
562 pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)));
563 return;
564 }
565
566 printf(_("Client #%u\n"
567 "\tDriver: %s\n"
568 "\tOwner Module: %s\n"
569 "\tProperties:\n\t\t%s\n"),
570 i->index,
571 pa_strnull(i->driver),
572 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
573 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
574
575 pa_xfree(pl);
576 }
577
get_card_info_callback(pa_context * c,const pa_card_info * i,int is_last,void * userdata)578 static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_last, void *userdata) {
579 char t[32];
580 char *pl;
581
582 if (is_last < 0) {
583 pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c)));
584 complete_action();
585 return;
586 }
587
588 if (is_last) {
589 complete_action();
590 return;
591 }
592
593 pa_assert(i);
594
595 if (nl && !short_list_format)
596 printf("\n");
597 nl = true;
598
599 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
600
601 if (short_list_format) {
602 printf("%u\t%s\t%s\n", i->index, i->name, pa_strnull(i->driver));
603 return;
604 }
605
606 printf(_("Card #%u\n"
607 "\tName: %s\n"
608 "\tDriver: %s\n"
609 "\tOwner Module: %s\n"
610 "\tProperties:\n\t\t%s\n"),
611 i->index,
612 i->name,
613 pa_strnull(i->driver),
614 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
615 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
616
617 pa_xfree(pl);
618
619 if (i->n_profiles > 0) {
620 pa_card_profile_info2 **p;
621
622 printf(_("\tProfiles:\n"));
623 for (p = i->profiles2; *p; p++)
624 printf(_("\t\t%s: %s (sinks: %u, sources: %u, priority: %u, available: %s)\n"), (*p)->name,
625 (*p)->description, (*p)->n_sinks, (*p)->n_sources, (*p)->priority, pa_yes_no_localised((*p)->available));
626 }
627
628 if (i->active_profile)
629 printf(_("\tActive Profile: %s\n"),
630 i->active_profile->name);
631
632 if (i->ports) {
633 pa_card_port_info **p;
634
635 printf(_("\tPorts:\n"));
636 for (p = i->ports; *p; p++) {
637 pa_card_profile_info **pr = (*p)->profiles;
638 printf(_("\t\t%s: %s (type: %s, priority: %u, latency offset: %" PRId64 " usec%s%s, %s)\n"), (*p)->name,
639 (*p)->description, get_device_port_type((*p)->type), (*p)->priority, (*p)->latency_offset,
640 (*p)->availability_group ? _(", availability group: ") : "", (*p)->availability_group ?: "",
641 get_available_str((*p)->available));
642
643 if (!pa_proplist_isempty((*p)->proplist)) {
644 printf(_("\t\t\tProperties:\n\t\t\t\t%s\n"), pl = pa_proplist_to_string_sep((*p)->proplist, "\n\t\t\t\t"));
645 pa_xfree(pl);
646 }
647
648 if (pr) {
649 printf(_("\t\t\tPart of profile(s): %s"), pa_strnull((*pr)->name));
650 pr++;
651 while (*pr) {
652 printf(", %s", pa_strnull((*pr)->name));
653 pr++;
654 }
655 printf("\n");
656 }
657 }
658 }
659 }
660
get_sink_input_info_callback(pa_context * c,const pa_sink_input_info * i,int is_last,void * userdata)661 static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
662 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], f[PA_FORMAT_INFO_SNPRINT_MAX];
663 char *pl;
664
665 if (is_last < 0) {
666 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
667 quit(1);
668 return;
669 }
670
671 if (is_last) {
672 complete_action();
673 return;
674 }
675
676 pa_assert(i);
677
678 if (nl && !short_list_format)
679 printf("\n");
680 nl = true;
681
682 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
683 pa_snprintf(k, sizeof(k), "%u", i->client);
684
685 if (short_list_format) {
686 printf("%u\t%u\t%s\t%s\t%s\n",
687 i->index,
688 i->sink,
689 i->client != PA_INVALID_INDEX ? k : "-",
690 pa_strnull(i->driver),
691 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
692 return;
693 }
694
695 printf(_("Sink Input #%u\n"
696 "\tDriver: %s\n"
697 "\tOwner Module: %s\n"
698 "\tClient: %s\n"
699 "\tSink: %u\n"
700 "\tSample Specification: %s\n"
701 "\tChannel Map: %s\n"
702 "\tFormat: %s\n"
703 "\tCorked: %s\n"
704 "\tMute: %s\n"
705 "\tVolume: %s\n"
706 "\t balance %0.2f\n"
707 "\tBuffer Latency: %0.0f usec\n"
708 "\tSink Latency: %0.0f usec\n"
709 "\tResample method: %s\n"
710 "\tProperties:\n\t\t%s\n"),
711 i->index,
712 pa_strnull(i->driver),
713 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
714 i->client != PA_INVALID_INDEX ? k : _("n/a"),
715 i->sink,
716 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
717 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
718 pa_format_info_snprint(f, sizeof(f), i->format),
719 pa_yes_no_localised(i->corked),
720 pa_yes_no_localised(i->mute),
721 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
722 pa_cvolume_get_balance(&i->volume, &i->channel_map),
723 (double) i->buffer_usec,
724 (double) i->sink_usec,
725 i->resample_method ? i->resample_method : _("n/a"),
726 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
727
728 pa_xfree(pl);
729 }
730
get_source_output_info_callback(pa_context * c,const pa_source_output_info * i,int is_last,void * userdata)731 static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) {
732 char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], f[PA_FORMAT_INFO_SNPRINT_MAX];
733 char *pl;
734
735 if (is_last < 0) {
736 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
737 quit(1);
738 return;
739 }
740
741 if (is_last) {
742 complete_action();
743 return;
744 }
745
746 pa_assert(i);
747
748 if (nl && !short_list_format)
749 printf("\n");
750 nl = true;
751
752 pa_snprintf(t, sizeof(t), "%u", i->owner_module);
753 pa_snprintf(k, sizeof(k), "%u", i->client);
754
755 if (short_list_format) {
756 printf("%u\t%u\t%s\t%s\t%s\n",
757 i->index,
758 i->source,
759 i->client != PA_INVALID_INDEX ? k : "-",
760 pa_strnull(i->driver),
761 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec));
762 return;
763 }
764
765 printf(_("Source Output #%u\n"
766 "\tDriver: %s\n"
767 "\tOwner Module: %s\n"
768 "\tClient: %s\n"
769 "\tSource: %u\n"
770 "\tSample Specification: %s\n"
771 "\tChannel Map: %s\n"
772 "\tFormat: %s\n"
773 "\tCorked: %s\n"
774 "\tMute: %s\n"
775 "\tVolume: %s\n"
776 "\t balance %0.2f\n"
777 "\tBuffer Latency: %0.0f usec\n"
778 "\tSource Latency: %0.0f usec\n"
779 "\tResample method: %s\n"
780 "\tProperties:\n\t\t%s\n"),
781 i->index,
782 pa_strnull(i->driver),
783 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"),
784 i->client != PA_INVALID_INDEX ? k : _("n/a"),
785 i->source,
786 pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
787 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
788 pa_format_info_snprint(f, sizeof(f), i->format),
789 pa_yes_no_localised(i->corked),
790 pa_yes_no_localised(i->mute),
791 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
792 pa_cvolume_get_balance(&i->volume, &i->channel_map),
793 (double) i->buffer_usec,
794 (double) i->source_usec,
795 i->resample_method ? i->resample_method : _("n/a"),
796 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
797
798 pa_xfree(pl);
799 }
800
get_sample_info_callback(pa_context * c,const pa_sample_info * i,int is_last,void * userdata)801 static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) {
802 char t[PA_BYTES_SNPRINT_MAX], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
803 char *pl;
804
805 if (is_last < 0) {
806 pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c)));
807 quit(1);
808 return;
809 }
810
811 if (is_last) {
812 complete_action();
813 return;
814 }
815
816 pa_assert(i);
817
818 if (nl && !short_list_format)
819 printf("\n");
820 nl = true;
821
822 pa_bytes_snprint(t, sizeof(t), i->bytes);
823
824 if (short_list_format) {
825 printf("%u\t%s\t%s\t%0.3f\n",
826 i->index,
827 i->name,
828 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "-",
829 (double) i->duration/1000000.0);
830 return;
831 }
832
833 printf(_("Sample #%u\n"
834 "\tName: %s\n"
835 "\tSample Specification: %s\n"
836 "\tChannel Map: %s\n"
837 "\tVolume: %s\n"
838 "\t balance %0.2f\n"
839 "\tDuration: %0.1fs\n"
840 "\tSize: %s\n"
841 "\tLazy: %s\n"
842 "\tFilename: %s\n"
843 "\tProperties:\n\t\t%s\n"),
844 i->index,
845 i->name,
846 pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : _("n/a"),
847 pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"),
848 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true),
849 pa_cvolume_get_balance(&i->volume, &i->channel_map),
850 (double) i->duration/1000000.0,
851 t,
852 pa_yes_no_localised(i->lazy),
853 i->filename ? i->filename : _("n/a"),
854 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));
855
856 pa_xfree(pl);
857 }
858
simple_callback(pa_context * c,int success,void * userdata)859 static void simple_callback(pa_context *c, int success, void *userdata) {
860 if (!success) {
861 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
862 quit(1);
863 return;
864 }
865
866 complete_action();
867 }
868
index_callback(pa_context * c,uint32_t idx,void * userdata)869 static void index_callback(pa_context *c, uint32_t idx, void *userdata) {
870 if (idx == PA_INVALID_INDEX) {
871 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c)));
872 quit(1);
873 return;
874 }
875
876 printf("%u\n", idx);
877
878 complete_action();
879 }
880
volume_relative_adjust(pa_cvolume * cv)881 static void volume_relative_adjust(pa_cvolume *cv) {
882 pa_assert(volume_flags & VOL_RELATIVE);
883
884 /* Relative volume change is additive in case of UINT or PERCENT
885 * and multiplicative for LINEAR or DECIBEL */
886 if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
887 unsigned i;
888 for (i = 0; i < cv->channels; i++) {
889 if (cv->values[i] + volume.values[i] < PA_VOLUME_NORM)
890 cv->values[i] = PA_VOLUME_MUTED;
891 else
892 cv->values[i] = cv->values[i] + volume.values[i] - PA_VOLUME_NORM;
893 }
894 }
895 if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL)
896 pa_sw_cvolume_multiply(cv, cv, &volume);
897 }
898
unload_module_by_name_callback(pa_context * c,const pa_module_info * i,int is_last,void * userdata)899 static void unload_module_by_name_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) {
900 static bool unloaded = false;
901
902 if (is_last < 0) {
903 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c)));
904 quit(1);
905 return;
906 }
907
908 if (is_last) {
909 if (unloaded == false)
910 pa_log(_("Failed to unload module: Module %s not loaded"), module_name);
911 complete_action();
912 return;
913 }
914
915 pa_assert(i);
916
917 if (pa_streq(module_name, i->name)) {
918 unloaded = true;
919 actions++;
920 pa_operation_unref(pa_context_unload_module(c, i->index, simple_callback, NULL));
921 }
922 }
923
fill_volume(pa_cvolume * cv,unsigned supported)924 static void fill_volume(pa_cvolume *cv, unsigned supported) {
925 if (volume.channels == 1) {
926 pa_cvolume_set(&volume, supported, volume.values[0]);
927 } else if (volume.channels != supported) {
928 pa_log(ngettext("Failed to set volume: You tried to set volumes for %d channel, whereas channel(s) supported = %d\n",
929 "Failed to set volume: You tried to set volumes for %d channels, whereas channel(s) supported = %d\n",
930 volume.channels),
931 volume.channels, supported);
932 quit(1);
933 return;
934 }
935
936 if (volume_flags & VOL_RELATIVE)
937 volume_relative_adjust(cv);
938 else
939 *cv = volume;
940 }
941
get_sink_volume_callback(pa_context * c,const pa_sink_info * i,int is_last,void * userdata)942 static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
943 pa_cvolume cv;
944
945 if (is_last < 0) {
946 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
947 quit(1);
948 return;
949 }
950
951 if (is_last)
952 return;
953
954 pa_assert(i);
955
956 cv = i->volume;
957 fill_volume(&cv, i->channel_map.channels);
958
959 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
960 }
961
get_source_volume_callback(pa_context * c,const pa_source_info * i,int is_last,void * userdata)962 static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
963 pa_cvolume cv;
964
965 if (is_last < 0) {
966 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
967 quit(1);
968 return;
969 }
970
971 if (is_last)
972 return;
973
974 pa_assert(i);
975
976 cv = i->volume;
977 fill_volume(&cv, i->channel_map.channels);
978
979 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
980 }
981
get_sink_input_volume_callback(pa_context * c,const pa_sink_input_info * i,int is_last,void * userdata)982 static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
983 pa_cvolume cv;
984
985 if (is_last < 0) {
986 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
987 quit(1);
988 return;
989 }
990
991 if (is_last)
992 return;
993
994 pa_assert(i);
995
996 cv = i->volume;
997 fill_volume(&cv, i->channel_map.channels);
998
999 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
1000 }
1001
get_source_output_volume_callback(pa_context * c,const pa_source_output_info * o,int is_last,void * userdata)1002 static void get_source_output_volume_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) {
1003 pa_cvolume cv;
1004
1005 if (is_last < 0) {
1006 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
1007 quit(1);
1008 return;
1009 }
1010
1011 if (is_last)
1012 return;
1013
1014 pa_assert(o);
1015
1016 cv = o->volume;
1017 fill_volume(&cv, o->channel_map.channels);
1018
1019 pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL));
1020 }
1021
sink_toggle_mute_callback(pa_context * c,const pa_sink_info * i,int is_last,void * userdata)1022 static void sink_toggle_mute_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
1023 if (is_last < 0) {
1024 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
1025 quit(1);
1026 return;
1027 }
1028
1029 if (is_last)
1030 return;
1031
1032 pa_assert(i);
1033
1034 pa_operation_unref(pa_context_set_sink_mute_by_name(c, i->name, !i->mute, simple_callback, NULL));
1035 }
1036
source_toggle_mute_callback(pa_context * c,const pa_source_info * o,int is_last,void * userdata)1037 static void source_toggle_mute_callback(pa_context *c, const pa_source_info *o, int is_last, void *userdata) {
1038 if (is_last < 0) {
1039 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
1040 quit(1);
1041 return;
1042 }
1043
1044 if (is_last)
1045 return;
1046
1047 pa_assert(o);
1048
1049 pa_operation_unref(pa_context_set_source_mute_by_name(c, o->name, !o->mute, simple_callback, NULL));
1050 }
1051
sink_input_toggle_mute_callback(pa_context * c,const pa_sink_input_info * i,int is_last,void * userdata)1052 static void sink_input_toggle_mute_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
1053 if (is_last < 0) {
1054 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
1055 quit(1);
1056 return;
1057 }
1058
1059 if (is_last)
1060 return;
1061
1062 pa_assert(i);
1063
1064 pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, !i->mute, simple_callback, NULL));
1065 }
1066
source_output_toggle_mute_callback(pa_context * c,const pa_source_output_info * o,int is_last,void * userdata)1067 static void source_output_toggle_mute_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) {
1068 if (is_last < 0) {
1069 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
1070 quit(1);
1071 return;
1072 }
1073
1074 if (is_last)
1075 return;
1076
1077 pa_assert(o);
1078
1079 pa_operation_unref(pa_context_set_source_output_mute(c, o->index, !o->mute, simple_callback, NULL));
1080 }
1081
1082 /* PA_MAX_FORMATS is defined in internal.h so we just define a sane value here */
1083 #define MAX_FORMATS 256
1084
set_sink_formats(pa_context * c,uint32_t sink,const char * str)1085 static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) {
1086 pa_format_info *f_arr[MAX_FORMATS] = { 0, };
1087 char *format = NULL;
1088 const char *state = NULL;
1089 int i = 0;
1090 pa_operation *o = NULL;
1091
1092 while ((format = pa_split(str, ";", &state))) {
1093 pa_format_info *f = pa_format_info_from_string(pa_strip(format));
1094
1095 if (!f) {
1096 pa_log(_("Failed to set format: invalid format string %s"), format);
1097 goto error;
1098 }
1099
1100 f_arr[i++] = f;
1101 pa_xfree(format);
1102 }
1103
1104 o = pa_ext_device_restore_save_formats(c, PA_DEVICE_TYPE_SINK, sink, i, f_arr, simple_callback, NULL);
1105 if (o) {
1106 pa_operation_unref(o);
1107 actions++;
1108 }
1109
1110 done:
1111 if (format)
1112 pa_xfree(format);
1113 while (f_arr[i] && i--)
1114 pa_format_info_free(f_arr[i]);
1115
1116 return;
1117
1118 error:
1119 while (f_arr[i] && i--)
1120 pa_format_info_free(f_arr[i]);
1121 quit(1);
1122 goto done;
1123 }
1124
stream_state_callback(pa_stream * s,void * userdata)1125 static void stream_state_callback(pa_stream *s, void *userdata) {
1126 pa_assert(s);
1127
1128 switch (pa_stream_get_state(s)) {
1129 case PA_STREAM_CREATING:
1130 case PA_STREAM_READY:
1131 break;
1132
1133 case PA_STREAM_TERMINATED:
1134 drain();
1135 break;
1136
1137 case PA_STREAM_FAILED:
1138 default:
1139 pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s))));
1140 quit(1);
1141 }
1142 }
1143
stream_write_callback(pa_stream * s,size_t length,void * userdata)1144 static void stream_write_callback(pa_stream *s, size_t length, void *userdata) {
1145 sf_count_t l;
1146 float *d;
1147 pa_assert(s && length && sndfile);
1148
1149 d = pa_xmalloc(length);
1150
1151 pa_assert(sample_length >= length);
1152 l = (sf_count_t) (length/pa_frame_size(&sample_spec));
1153
1154 if ((sf_readf_float(sndfile, d, l)) != l) {
1155 pa_xfree(d);
1156 pa_log(_("Premature end of file"));
1157 quit(1);
1158 return;
1159 }
1160
1161 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE);
1162
1163 sample_length -= length;
1164
1165 if (sample_length <= 0) {
1166 pa_stream_set_write_callback(sample_stream, NULL, NULL);
1167 pa_stream_finish_upload(sample_stream);
1168 }
1169 }
1170
subscription_event_type_to_string(pa_subscription_event_type_t t)1171 static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) {
1172
1173 switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) {
1174
1175 case PA_SUBSCRIPTION_EVENT_NEW:
1176 return _("new");
1177
1178 case PA_SUBSCRIPTION_EVENT_CHANGE:
1179 return _("change");
1180
1181 case PA_SUBSCRIPTION_EVENT_REMOVE:
1182 return _("remove");
1183 }
1184
1185 return _("unknown");
1186 }
1187
subscription_event_facility_to_string(pa_subscription_event_type_t t)1188 static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) {
1189
1190 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
1191
1192 case PA_SUBSCRIPTION_EVENT_SINK:
1193 return _("sink");
1194
1195 case PA_SUBSCRIPTION_EVENT_SOURCE:
1196 return _("source");
1197
1198 case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
1199 return _("sink-input");
1200
1201 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
1202 return _("source-output");
1203
1204 case PA_SUBSCRIPTION_EVENT_MODULE:
1205 return _("module");
1206
1207 case PA_SUBSCRIPTION_EVENT_CLIENT:
1208 return _("client");
1209
1210 case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
1211 return _("sample-cache");
1212
1213 case PA_SUBSCRIPTION_EVENT_SERVER:
1214 return _("server");
1215
1216 case PA_SUBSCRIPTION_EVENT_CARD:
1217 return _("card");
1218 }
1219
1220 return _("unknown");
1221 }
1222
context_subscribe_callback(pa_context * c,pa_subscription_event_type_t t,uint32_t idx,void * userdata)1223 static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
1224 pa_assert(c);
1225
1226 printf(_("Event '%s' on %s #%u\n"),
1227 subscription_event_type_to_string(t),
1228 subscription_event_facility_to_string(t),
1229 idx);
1230 fflush(stdout);
1231 }
1232
context_state_callback(pa_context * c,void * userdata)1233 static void context_state_callback(pa_context *c, void *userdata) {
1234 pa_operation *o = NULL;
1235
1236 pa_assert(c);
1237
1238 switch (pa_context_get_state(c)) {
1239 case PA_CONTEXT_CONNECTING:
1240 case PA_CONTEXT_AUTHORIZING:
1241 case PA_CONTEXT_SETTING_NAME:
1242 break;
1243
1244 case PA_CONTEXT_READY:
1245 switch (action) {
1246 case STAT:
1247 o = pa_context_stat(c, stat_callback, NULL);
1248 break;
1249
1250 case INFO:
1251 o = pa_context_get_server_info(c, get_server_info_callback, NULL);
1252 break;
1253
1254 case PLAY_SAMPLE:
1255 o = pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL);
1256 break;
1257
1258 case REMOVE_SAMPLE:
1259 o = pa_context_remove_sample(c, sample_name, simple_callback, NULL);
1260 break;
1261
1262 case UPLOAD_SAMPLE:
1263 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL);
1264 pa_assert(sample_stream);
1265
1266 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
1267 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
1268 pa_stream_connect_upload(sample_stream, sample_length);
1269 actions++;
1270 break;
1271
1272 case EXIT:
1273 o = pa_context_exit_daemon(c, simple_callback, NULL);
1274 break;
1275
1276 case LIST:
1277 if (list_type) {
1278 if (pa_streq(list_type, "modules"))
1279 o = pa_context_get_module_info_list(c, get_module_info_callback, NULL);
1280 else if (pa_streq(list_type, "sinks"))
1281 o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL);
1282 else if (pa_streq(list_type, "sources"))
1283 o = pa_context_get_source_info_list(c, get_source_info_callback, NULL);
1284 else if (pa_streq(list_type, "sink-inputs"))
1285 o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL);
1286 else if (pa_streq(list_type, "source-outputs"))
1287 o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL);
1288 else if (pa_streq(list_type, "clients"))
1289 o = pa_context_get_client_info_list(c, get_client_info_callback, NULL);
1290 else if (pa_streq(list_type, "samples"))
1291 o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL);
1292 else if (pa_streq(list_type, "cards"))
1293 o = pa_context_get_card_info_list(c, get_card_info_callback, NULL);
1294 else
1295 pa_assert_not_reached();
1296 } else {
1297 o = pa_context_get_module_info_list(c, get_module_info_callback, NULL);
1298 if (o) {
1299 pa_operation_unref(o);
1300 actions++;
1301 }
1302
1303 o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL);
1304 if (o) {
1305 pa_operation_unref(o);
1306 actions++;
1307 }
1308
1309 o = pa_context_get_source_info_list(c, get_source_info_callback, NULL);
1310 if (o) {
1311 pa_operation_unref(o);
1312 actions++;
1313 }
1314 o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL);
1315 if (o) {
1316 pa_operation_unref(o);
1317 actions++;
1318 }
1319
1320 o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL);
1321 if (o) {
1322 pa_operation_unref(o);
1323 actions++;
1324 }
1325
1326 o = pa_context_get_client_info_list(c, get_client_info_callback, NULL);
1327 if (o) {
1328 pa_operation_unref(o);
1329 actions++;
1330 }
1331
1332 o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL);
1333 if (o) {
1334 pa_operation_unref(o);
1335 actions++;
1336 }
1337
1338 o = pa_context_get_card_info_list(c, get_card_info_callback, NULL);
1339 if (o) {
1340 pa_operation_unref(o);
1341 actions++;
1342 }
1343
1344 o = NULL;
1345 }
1346 break;
1347
1348 case MOVE_SINK_INPUT:
1349 o = pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL);
1350 break;
1351
1352 case MOVE_SOURCE_OUTPUT:
1353 o = pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL);
1354 break;
1355
1356 case LOAD_MODULE:
1357 o = pa_context_load_module(c, module_name, module_args, index_callback, NULL);
1358 break;
1359
1360 case UNLOAD_MODULE:
1361 if (module_name)
1362 o = pa_context_get_module_info_list(c, unload_module_by_name_callback, NULL);
1363 else
1364 o = pa_context_unload_module(c, module_index, simple_callback, NULL);
1365 break;
1366
1367 case SUSPEND_SINK:
1368 if (sink_name)
1369 o = pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL);
1370 else
1371 o = pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL);
1372 break;
1373
1374 case SUSPEND_SOURCE:
1375 if (source_name)
1376 o = pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL);
1377 else
1378 o = pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL);
1379 break;
1380
1381 case SET_CARD_PROFILE:
1382 o = pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL);
1383 break;
1384
1385 case SET_SINK_PORT:
1386 o = pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL);
1387 break;
1388
1389 case SET_DEFAULT_SINK:
1390 o = pa_context_set_default_sink(c, sink_name, simple_callback, NULL);
1391 break;
1392
1393 case SET_SOURCE_PORT:
1394 o = pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL);
1395 break;
1396
1397 case SET_DEFAULT_SOURCE:
1398 o = pa_context_set_default_source(c, source_name, simple_callback, NULL);
1399 break;
1400
1401 case SET_SINK_MUTE:
1402 if (mute == TOGGLE_MUTE)
1403 o = pa_context_get_sink_info_by_name(c, sink_name, sink_toggle_mute_callback, NULL);
1404 else
1405 o = pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL);
1406 break;
1407
1408 case SET_SOURCE_MUTE:
1409 if (mute == TOGGLE_MUTE)
1410 o = pa_context_get_source_info_by_name(c, source_name, source_toggle_mute_callback, NULL);
1411 else
1412 o = pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL);
1413 break;
1414
1415 case SET_SINK_INPUT_MUTE:
1416 if (mute == TOGGLE_MUTE)
1417 o = pa_context_get_sink_input_info(c, sink_input_idx, sink_input_toggle_mute_callback, NULL);
1418 else
1419 o = pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL);
1420 break;
1421
1422 case SET_SOURCE_OUTPUT_MUTE:
1423 if (mute == TOGGLE_MUTE)
1424 o = pa_context_get_source_output_info(c, source_output_idx, source_output_toggle_mute_callback, NULL);
1425 else
1426 o = pa_context_set_source_output_mute(c, source_output_idx, mute, simple_callback, NULL);
1427 break;
1428
1429 case SET_SINK_VOLUME:
1430 o = pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL);
1431 break;
1432
1433 case SET_SOURCE_VOLUME:
1434 o = pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL);
1435 break;
1436
1437 case SET_SINK_INPUT_VOLUME:
1438 o = pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL);
1439 break;
1440
1441 case SET_SOURCE_OUTPUT_VOLUME:
1442 o = pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL);
1443 break;
1444
1445 case SET_SINK_FORMATS:
1446 set_sink_formats(c, sink_idx, formats);
1447 break;
1448
1449 case SET_PORT_LATENCY_OFFSET:
1450 o = pa_context_set_port_latency_offset(c, card_name, port_name, latency_offset, simple_callback, NULL);
1451 break;
1452
1453 case SUBSCRIBE:
1454 pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL);
1455
1456 o = pa_context_subscribe(c,
1457 PA_SUBSCRIPTION_MASK_SINK|
1458 PA_SUBSCRIPTION_MASK_SOURCE|
1459 PA_SUBSCRIPTION_MASK_SINK_INPUT|
1460 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
1461 PA_SUBSCRIPTION_MASK_MODULE|
1462 PA_SUBSCRIPTION_MASK_CLIENT|
1463 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE|
1464 PA_SUBSCRIPTION_MASK_SERVER|
1465 PA_SUBSCRIPTION_MASK_CARD,
1466 NULL,
1467 NULL);
1468 break;
1469
1470 default:
1471 pa_assert_not_reached();
1472 }
1473
1474 if (o) {
1475 pa_operation_unref(o);
1476 actions++;
1477 }
1478
1479 if (actions == 0) {
1480 pa_log("Operation failed: %s", pa_strerror(pa_context_errno(c)));
1481 quit(1);
1482 }
1483
1484 break;
1485
1486 case PA_CONTEXT_TERMINATED:
1487 quit(0);
1488 break;
1489
1490 case PA_CONTEXT_FAILED:
1491 default:
1492 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c)));
1493 quit(1);
1494 }
1495 }
1496
exit_signal_callback(pa_mainloop_api * m,pa_signal_event * e,int sig,void * userdata)1497 static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) {
1498 pa_log(_("Got SIGINT, exiting."));
1499 quit(0);
1500 }
1501
parse_volume(const char * vol_spec,pa_volume_t * vol,enum volume_flags * vol_flags)1502 static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) {
1503 double v;
1504 char *vs;
1505 const char *atod_input;
1506
1507 pa_assert(vol_spec);
1508 pa_assert(vol);
1509 pa_assert(vol_flags);
1510
1511 vs = pa_xstrdup(vol_spec);
1512
1513 *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE;
1514 if (strchr(vs, '.'))
1515 *vol_flags |= VOL_LINEAR;
1516 if (pa_endswith(vs, "%")) {
1517 *vol_flags |= VOL_PERCENT;
1518 vs[strlen(vs)-1] = 0;
1519 }
1520 if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) {
1521 *vol_flags |= VOL_DECIBEL;
1522 vs[strlen(vs)-2] = 0;
1523 }
1524
1525 atod_input = vs;
1526
1527 if (atod_input[0] == '+')
1528 atod_input++; /* pa_atod() doesn't accept leading '+', so skip it. */
1529
1530 if (pa_atod(atod_input, &v) < 0) {
1531 pa_log(_("Invalid volume specification"));
1532 pa_xfree(vs);
1533 return -1;
1534 }
1535
1536 pa_xfree(vs);
1537
1538 if (*vol_flags & VOL_RELATIVE) {
1539 if ((*vol_flags & 0x0F) == VOL_UINT)
1540 v += (double) PA_VOLUME_NORM;
1541 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1542 v += 100.0;
1543 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1544 v += 1.0;
1545 }
1546 if ((*vol_flags & 0x0F) == VOL_PERCENT)
1547 v = v * (double) PA_VOLUME_NORM / 100;
1548 if ((*vol_flags & 0x0F) == VOL_LINEAR)
1549 v = pa_sw_volume_from_linear(v);
1550 if ((*vol_flags & 0x0F) == VOL_DECIBEL)
1551 v = pa_sw_volume_from_dB(v);
1552
1553 if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) {
1554 pa_log(_("Volume outside permissible range.\n"));
1555 return -1;
1556 }
1557
1558 *vol = (pa_volume_t) v;
1559
1560 return 0;
1561 }
1562
parse_volumes(char * args[],unsigned n)1563 static int parse_volumes(char *args[], unsigned n) {
1564 unsigned i;
1565
1566 if (n >= PA_CHANNELS_MAX) {
1567 pa_log(_("Invalid number of volume specifications.\n"));
1568 return -1;
1569 }
1570
1571 volume.channels = n;
1572 for (i = 0; i < volume.channels; i++) {
1573 enum volume_flags flags;
1574
1575 if (parse_volume(args[i], &volume.values[i], &flags) < 0)
1576 return -1;
1577
1578 if (i > 0 && flags != volume_flags) {
1579 pa_log(_("Inconsistent volume specification.\n"));
1580 return -1;
1581 } else
1582 volume_flags = flags;
1583 }
1584
1585 return 0;
1586 }
1587
parse_mute(const char * mute_text)1588 static enum mute_flags parse_mute(const char *mute_text) {
1589 int b;
1590
1591 pa_assert(mute_text);
1592
1593 if (pa_streq("toggle", mute_text))
1594 return TOGGLE_MUTE;
1595
1596 b = pa_parse_boolean(mute_text);
1597 switch (b) {
1598 case 0:
1599 return UNMUTE;
1600 case 1:
1601 return MUTE;
1602 default:
1603 return INVALID_MUTE;
1604 }
1605 }
1606
help(const char * argv0)1607 static void help(const char *argv0) {
1608
1609 printf("%s %s %s\n", argv0, _("[options]"), "stat");
1610 printf("%s %s %s\n", argv0, _("[options]"), "info");
1611 printf("%s %s %s %s\n", argv0, _("[options]"), "list [short]", _("[TYPE]"));
1612 printf("%s %s %s\n", argv0, _("[options]"), "exit");
1613 printf("%s %s %s %s\n", argv0, _("[options]"), "upload-sample", _("FILENAME [NAME]"));
1614 printf("%s %s %s %s\n", argv0, _("[options]"), "play-sample ", _("NAME [SINK]"));
1615 printf("%s %s %s %s\n", argv0, _("[options]"), "remove-sample ", _("NAME"));
1616 printf("%s %s %s %s\n", argv0, _("[options]"), "load-module ", _("NAME [ARGS ...]"));
1617 printf("%s %s %s %s\n", argv0, _("[options]"), "unload-module ", _("NAME|#N"));
1618 printf("%s %s %s %s\n", argv0, _("[options]"), "move-(sink-input|source-output)", _("#N SINK|SOURCE"));
1619 printf("%s %s %s %s\n", argv0, _("[options]"), "suspend-(sink|source)", _("NAME|#N 1|0"));
1620 printf("%s %s %s %s\n", argv0, _("[options]"), "set-card-profile ", _("CARD PROFILE"));
1621 printf("%s %s %s %s\n", argv0, _("[options]"), "set-default-(sink|source)", _("NAME"));
1622 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-port", _("NAME|#N PORT"));
1623 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-volume", _("NAME|#N VOLUME [VOLUME ...]"));
1624 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-volume", _("#N VOLUME [VOLUME ...]"));
1625 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-mute", _("NAME|#N 1|0|toggle"));
1626 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-mute", _("#N 1|0|toggle"));
1627 printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats", _("#N FORMATS"));
1628 printf("%s %s %s %s\n", argv0, _("[options]"), "set-port-latency-offset", _("CARD-NAME|CARD-#N PORT OFFSET"));
1629 printf("%s %s %s\n", argv0, _("[options]"), "subscribe");
1630 printf(_("\nThe special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and @DEFAULT_MONITOR@\n"
1631 "can be used to specify the default sink, source and monitor.\n"));
1632
1633 printf(_("\n"
1634 " -h, --help Show this help\n"
1635 " --version Show version\n\n"
1636 " -s, --server=SERVER The name of the server to connect to\n"
1637 " -n, --client-name=NAME How to call this client on the server\n"));
1638 }
1639
1640 enum {
1641 ARG_VERSION = 256
1642 };
1643
main(int argc,char * argv[])1644 int main(int argc, char *argv[]) {
1645 pa_mainloop *m = NULL;
1646 int ret = 1, c;
1647 char *server = NULL, *bn;
1648
1649 static const struct option long_options[] = {
1650 {"server", 1, NULL, 's'},
1651 {"client-name", 1, NULL, 'n'},
1652 {"version", 0, NULL, ARG_VERSION},
1653 {"help", 0, NULL, 'h'},
1654 {NULL, 0, NULL, 0}
1655 };
1656
1657 setlocale(LC_ALL, "");
1658 #ifdef ENABLE_NLS
1659 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
1660 #endif
1661
1662 bn = pa_path_get_filename(argv[0]);
1663
1664 proplist = pa_proplist_new();
1665
1666 while ((c = getopt_long(argc, argv, "+s:n:h", long_options, NULL)) != -1) {
1667 switch (c) {
1668 case 'h' :
1669 help(bn);
1670 ret = 0;
1671 goto quit;
1672
1673 case ARG_VERSION:
1674 printf(_("pactl %s\n"
1675 "Compiled with libpulse %s\n"
1676 "Linked with libpulse %s\n"),
1677 PACKAGE_VERSION,
1678 pa_get_headers_version(),
1679 pa_get_library_version());
1680 ret = 0;
1681 goto quit;
1682
1683 case 's':
1684 pa_xfree(server);
1685 server = pa_xstrdup(optarg);
1686 break;
1687
1688 case 'n': {
1689 char *t;
1690
1691 if (!(t = pa_locale_to_utf8(optarg)) ||
1692 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {
1693
1694 pa_log(_("Invalid client name '%s'"), t ? t : optarg);
1695 pa_xfree(t);
1696 goto quit;
1697 }
1698
1699 pa_xfree(t);
1700 break;
1701 }
1702
1703 default:
1704 goto quit;
1705 }
1706 }
1707
1708 if (optind < argc) {
1709 if (pa_streq(argv[optind], "stat")) {
1710 action = STAT;
1711
1712 } else if (pa_streq(argv[optind], "info"))
1713 action = INFO;
1714
1715 else if (pa_streq(argv[optind], "exit"))
1716 action = EXIT;
1717
1718 else if (pa_streq(argv[optind], "list")) {
1719 action = LIST;
1720
1721 for (int i = optind+1; i < argc; i++) {
1722 if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") ||
1723 pa_streq(argv[i], "sinks") || pa_streq(argv[i], "sink-inputs") ||
1724 pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") ||
1725 pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards")) {
1726 list_type = pa_xstrdup(argv[i]);
1727 } else if (pa_streq(argv[i], "short")) {
1728 short_list_format = true;
1729 } else {
1730 pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards");
1731 goto quit;
1732 }
1733 }
1734
1735 } else if (pa_streq(argv[optind], "upload-sample")) {
1736 struct SF_INFO sfi;
1737 action = UPLOAD_SAMPLE;
1738
1739 if (optind+1 >= argc) {
1740 pa_log(_("Please specify a sample file to load"));
1741 goto quit;
1742 }
1743
1744 if (optind+2 < argc)
1745 sample_name = pa_xstrdup(argv[optind+2]);
1746 else {
1747 char *f = pa_path_get_filename(argv[optind+1]);
1748 sample_name = pa_xstrndup(f, strcspn(f, "."));
1749 }
1750
1751 pa_zero(sfi);
1752 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) {
1753 pa_log(_("Failed to open sound file."));
1754 goto quit;
1755 }
1756
1757 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
1758 pa_log(_("Failed to determine sample specification from file."));
1759 goto quit;
1760 }
1761 sample_spec.format = PA_SAMPLE_FLOAT32;
1762
1763 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
1764 if (sample_spec.channels > 2)
1765 pa_log(_("Warning: Failed to determine sample specification from file."));
1766 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
1767 }
1768
1769 pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec));
1770 sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec);
1771
1772 } else if (pa_streq(argv[optind], "play-sample")) {
1773 action = PLAY_SAMPLE;
1774 if (argc != optind+2 && argc != optind+3) {
1775 pa_log(_("You have to specify a sample name to play"));
1776 goto quit;
1777 }
1778
1779 sample_name = pa_xstrdup(argv[optind+1]);
1780
1781 if (optind+2 < argc)
1782 sink_name = pa_xstrdup(argv[optind+2]);
1783
1784 } else if (pa_streq(argv[optind], "remove-sample")) {
1785 action = REMOVE_SAMPLE;
1786 if (argc != optind+2) {
1787 pa_log(_("You have to specify a sample name to remove"));
1788 goto quit;
1789 }
1790
1791 sample_name = pa_xstrdup(argv[optind+1]);
1792
1793 } else if (pa_streq(argv[optind], "move-sink-input")) {
1794 action = MOVE_SINK_INPUT;
1795 if (argc != optind+3) {
1796 pa_log(_("You have to specify a sink input index and a sink"));
1797 goto quit;
1798 }
1799
1800 sink_input_idx = (uint32_t) atoi(argv[optind+1]);
1801 sink_name = pa_xstrdup(argv[optind+2]);
1802
1803 } else if (pa_streq(argv[optind], "move-source-output")) {
1804 action = MOVE_SOURCE_OUTPUT;
1805 if (argc != optind+3) {
1806 pa_log(_("You have to specify a source output index and a source"));
1807 goto quit;
1808 }
1809
1810 source_output_idx = (uint32_t) atoi(argv[optind+1]);
1811 source_name = pa_xstrdup(argv[optind+2]);
1812
1813 } else if (pa_streq(argv[optind], "load-module")) {
1814 int i;
1815 size_t n = 0;
1816 char *p;
1817
1818 action = LOAD_MODULE;
1819
1820 if (argc <= optind+1) {
1821 pa_log(_("You have to specify a module name and arguments."));
1822 goto quit;
1823 }
1824
1825 module_name = argv[optind+1];
1826
1827 for (i = optind+2; i < argc; i++)
1828 n += strlen(argv[i])+1;
1829
1830 if (n > 0) {
1831 p = module_args = pa_xmalloc(n);
1832
1833 for (i = optind+2; i < argc; i++)
1834 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]);
1835 }
1836
1837 } else if (pa_streq(argv[optind], "unload-module")) {
1838 action = UNLOAD_MODULE;
1839
1840 if (argc != optind+2) {
1841 pa_log(_("You have to specify a module index or name"));
1842 goto quit;
1843 }
1844
1845 if (pa_atou(argv[optind + 1], &module_index) < 0)
1846 module_name = argv[optind + 1];
1847
1848 } else if (pa_streq(argv[optind], "suspend-sink")) {
1849 int b;
1850
1851 action = SUSPEND_SINK;
1852
1853 if (argc > optind+3 || optind+1 >= argc) {
1854 pa_log(_("You may not specify more than one sink. You have to specify a boolean value."));
1855 goto quit;
1856 }
1857
1858 if ((b = pa_parse_boolean(argv[argc-1])) < 0) {
1859 pa_log(_("Invalid suspend specification."));
1860 goto quit;
1861 }
1862
1863 suspend = !!b;
1864
1865 if (argc > optind+2)
1866 sink_name = pa_xstrdup(argv[optind+1]);
1867
1868 } else if (pa_streq(argv[optind], "suspend-source")) {
1869 int b;
1870
1871 action = SUSPEND_SOURCE;
1872
1873 if (argc > optind+3 || optind+1 >= argc) {
1874 pa_log(_("You may not specify more than one source. You have to specify a boolean value."));
1875 goto quit;
1876 }
1877
1878 if ((b = pa_parse_boolean(argv[argc-1])) < 0) {
1879 pa_log(_("Invalid suspend specification."));
1880 goto quit;
1881 }
1882
1883 suspend = !!b;
1884
1885 if (argc > optind+2)
1886 source_name = pa_xstrdup(argv[optind+1]);
1887 } else if (pa_streq(argv[optind], "set-card-profile")) {
1888 action = SET_CARD_PROFILE;
1889
1890 if (argc != optind+3) {
1891 pa_log(_("You have to specify a card name/index and a profile name"));
1892 goto quit;
1893 }
1894
1895 card_name = pa_xstrdup(argv[optind+1]);
1896 profile_name = pa_xstrdup(argv[optind+2]);
1897
1898 } else if (pa_streq(argv[optind], "set-sink-port")) {
1899 action = SET_SINK_PORT;
1900
1901 if (argc != optind+3) {
1902 pa_log(_("You have to specify a sink name/index and a port name"));
1903 goto quit;
1904 }
1905
1906 sink_name = pa_xstrdup(argv[optind+1]);
1907 port_name = pa_xstrdup(argv[optind+2]);
1908
1909 } else if (pa_streq(argv[optind], "set-default-sink")) {
1910 action = SET_DEFAULT_SINK;
1911
1912 if (argc != optind+2) {
1913 pa_log(_("You have to specify a sink name"));
1914 goto quit;
1915 }
1916
1917 sink_name = pa_xstrdup(argv[optind+1]);
1918
1919 } else if (pa_streq(argv[optind], "set-source-port")) {
1920 action = SET_SOURCE_PORT;
1921
1922 if (argc != optind+3) {
1923 pa_log(_("You have to specify a source name/index and a port name"));
1924 goto quit;
1925 }
1926
1927 source_name = pa_xstrdup(argv[optind+1]);
1928 port_name = pa_xstrdup(argv[optind+2]);
1929
1930 } else if (pa_streq(argv[optind], "set-default-source")) {
1931 action = SET_DEFAULT_SOURCE;
1932
1933 if (argc != optind+2) {
1934 pa_log(_("You have to specify a source name"));
1935 goto quit;
1936 }
1937
1938 source_name = pa_xstrdup(argv[optind+1]);
1939
1940 } else if (pa_streq(argv[optind], "set-sink-volume")) {
1941 action = SET_SINK_VOLUME;
1942
1943 if (argc < optind+3) {
1944 pa_log(_("You have to specify a sink name/index and a volume"));
1945 goto quit;
1946 }
1947
1948 sink_name = pa_xstrdup(argv[optind+1]);
1949
1950 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
1951 goto quit;
1952
1953 } else if (pa_streq(argv[optind], "set-source-volume")) {
1954 action = SET_SOURCE_VOLUME;
1955
1956 if (argc < optind+3) {
1957 pa_log(_("You have to specify a source name/index and a volume"));
1958 goto quit;
1959 }
1960
1961 source_name = pa_xstrdup(argv[optind+1]);
1962
1963 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
1964 goto quit;
1965
1966 } else if (pa_streq(argv[optind], "set-sink-input-volume")) {
1967 action = SET_SINK_INPUT_VOLUME;
1968
1969 if (argc < optind+3) {
1970 pa_log(_("You have to specify a sink input index and a volume"));
1971 goto quit;
1972 }
1973
1974 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
1975 pa_log(_("Invalid sink input index"));
1976 goto quit;
1977 }
1978
1979 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
1980 goto quit;
1981
1982 } else if (pa_streq(argv[optind], "set-source-output-volume")) {
1983 action = SET_SOURCE_OUTPUT_VOLUME;
1984
1985 if (argc < optind+3) {
1986 pa_log(_("You have to specify a source output index and a volume"));
1987 goto quit;
1988 }
1989
1990 if (pa_atou(argv[optind+1], &source_output_idx) < 0) {
1991 pa_log(_("Invalid source output index"));
1992 goto quit;
1993 }
1994
1995 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0)
1996 goto quit;
1997
1998 } else if (pa_streq(argv[optind], "set-sink-mute")) {
1999 action = SET_SINK_MUTE;
2000
2001 if (argc != optind+3) {
2002 pa_log(_("You have to specify a sink name/index and a mute action (0, 1, or 'toggle')"));
2003 goto quit;
2004 }
2005
2006 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
2007 pa_log(_("Invalid mute specification"));
2008 goto quit;
2009 }
2010
2011 sink_name = pa_xstrdup(argv[optind+1]);
2012
2013 } else if (pa_streq(argv[optind], "set-source-mute")) {
2014 action = SET_SOURCE_MUTE;
2015
2016 if (argc != optind+3) {
2017 pa_log(_("You have to specify a source name/index and a mute action (0, 1, or 'toggle')"));
2018 goto quit;
2019 }
2020
2021 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
2022 pa_log(_("Invalid mute specification"));
2023 goto quit;
2024 }
2025
2026 source_name = pa_xstrdup(argv[optind+1]);
2027
2028 } else if (pa_streq(argv[optind], "set-sink-input-mute")) {
2029 action = SET_SINK_INPUT_MUTE;
2030
2031 if (argc != optind+3) {
2032 pa_log(_("You have to specify a sink input index and a mute action (0, 1, or 'toggle')"));
2033 goto quit;
2034 }
2035
2036 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) {
2037 pa_log(_("Invalid sink input index specification"));
2038 goto quit;
2039 }
2040
2041 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
2042 pa_log(_("Invalid mute specification"));
2043 goto quit;
2044 }
2045
2046 } else if (pa_streq(argv[optind], "set-source-output-mute")) {
2047 action = SET_SOURCE_OUTPUT_MUTE;
2048
2049 if (argc != optind+3) {
2050 pa_log(_("You have to specify a source output index and a mute action (0, 1, or 'toggle')"));
2051 goto quit;
2052 }
2053
2054 if (pa_atou(argv[optind+1], &source_output_idx) < 0) {
2055 pa_log(_("Invalid source output index specification"));
2056 goto quit;
2057 }
2058
2059 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) {
2060 pa_log(_("Invalid mute specification"));
2061 goto quit;
2062 }
2063
2064 } else if (pa_streq(argv[optind], "subscribe"))
2065
2066 action = SUBSCRIBE;
2067
2068 else if (pa_streq(argv[optind], "set-sink-formats")) {
2069 int32_t tmp;
2070
2071 if (argc != optind+3 || pa_atoi(argv[optind+1], &tmp) < 0) {
2072 pa_log(_("You have to specify a sink index and a semicolon-separated list of supported formats"));
2073 goto quit;
2074 }
2075
2076 sink_idx = tmp;
2077 action = SET_SINK_FORMATS;
2078 formats = pa_xstrdup(argv[optind+2]);
2079
2080 } else if (pa_streq(argv[optind], "set-port-latency-offset")) {
2081 action = SET_PORT_LATENCY_OFFSET;
2082
2083 if (argc != optind+4) {
2084 pa_log(_("You have to specify a card name/index, a port name and a latency offset"));
2085 goto quit;
2086 }
2087
2088 card_name = pa_xstrdup(argv[optind+1]);
2089 port_name = pa_xstrdup(argv[optind+2]);
2090 if (pa_atoi(argv[optind + 3], &latency_offset) < 0) {
2091 pa_log(_("Could not parse latency offset"));
2092 goto quit;
2093 }
2094
2095 } else if (pa_streq(argv[optind], "help")) {
2096 help(bn);
2097 ret = 0;
2098 goto quit;
2099 }
2100 }
2101
2102 if (action == NONE) {
2103 pa_log(_("No valid command specified."));
2104 goto quit;
2105 }
2106
2107 if (!(m = pa_mainloop_new())) {
2108 pa_log(_("pa_mainloop_new() failed."));
2109 goto quit;
2110 }
2111
2112 mainloop_api = pa_mainloop_get_api(m);
2113
2114 pa_assert_se(pa_signal_init(mainloop_api) == 0);
2115 pa_signal_new(SIGINT, exit_signal_callback, NULL);
2116 pa_signal_new(SIGTERM, exit_signal_callback, NULL);
2117 pa_disable_sigpipe();
2118
2119 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
2120 pa_log(_("pa_context_new() failed."));
2121 goto quit;
2122 }
2123
2124 pa_context_set_state_callback(context, context_state_callback, NULL);
2125 if (pa_context_connect(context, server, 0, NULL) < 0) {
2126 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
2127 goto quit;
2128 }
2129
2130 if (pa_mainloop_run(m, &ret) < 0) {
2131 pa_log(_("pa_mainloop_run() failed."));
2132 goto quit;
2133 }
2134
2135 quit:
2136 if (sample_stream)
2137 pa_stream_unref(sample_stream);
2138
2139 if (context)
2140 pa_context_unref(context);
2141
2142 if (m) {
2143 pa_signal_done();
2144 pa_mainloop_free(m);
2145 }
2146
2147 pa_xfree(server);
2148 pa_xfree(list_type);
2149 pa_xfree(sample_name);
2150 pa_xfree(sink_name);
2151 pa_xfree(source_name);
2152 pa_xfree(module_args);
2153 pa_xfree(card_name);
2154 pa_xfree(profile_name);
2155 pa_xfree(port_name);
2156 pa_xfree(formats);
2157
2158 if (sndfile)
2159 sf_close(sndfile);
2160
2161 if (proplist)
2162 pa_proplist_free(proplist);
2163
2164 return ret;
2165 }
2166