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#ifdef SNDFILE_ENABLE 36#include <sndfile.h> 37#endif 38 39#include <pulse/pulseaudio.h> 40#include <pulse/ext-device-restore.h> 41#include <pulse/xmalloc.h> 42 43#include <pulsecore/i18n.h> 44#include <pulsecore/json.h> 45#include <pulsecore/macro.h> 46#include <pulsecore/core-util.h> 47#include <pulsecore/log.h> 48 49#ifdef SNDFILE_ENABLE 50#include <pulsecore/sndfile-util.h> 51#endif 52 53static pa_context *context = NULL; 54static pa_mainloop_api *mainloop_api = NULL; 55 56static char 57 *list_type = NULL, 58 *sample_name = NULL, 59 *sink_name = NULL, 60 *source_name = NULL, 61 *module_name = NULL, 62 *module_args = NULL, 63 *card_name = NULL, 64 *profile_name = NULL, 65 *port_name = NULL, 66 *formats = NULL, 67 *object_path = NULL, 68 *message = NULL, 69 *message_args = NULL; 70 71static uint32_t 72 sink_input_idx = PA_INVALID_INDEX, 73 source_output_idx = PA_INVALID_INDEX, 74 sink_idx = PA_INVALID_INDEX; 75 76static bool short_list_format = false; 77static uint32_t module_index; 78static int32_t latency_offset; 79static bool suspend; 80static pa_cvolume volume; 81static enum volume_flags { 82 VOL_UINT = 0, 83 VOL_PERCENT = 1, 84 VOL_LINEAR = 2, 85 VOL_DECIBEL = 3, 86 VOL_ABSOLUTE = 0 << 4, 87 VOL_RELATIVE = 1 << 4, 88} volume_flags; 89 90static enum mute_flags { 91 INVALID_MUTE = -1, 92 UNMUTE = 0, 93 MUTE = 1, 94 TOGGLE_MUTE = 2 95} mute = INVALID_MUTE; 96 97static pa_proplist *proplist = NULL; 98 99#ifdef SNDFILE_ENABLE 100static SNDFILE *sndfile = NULL; 101static pa_stream *sample_stream = NULL; 102static pa_sample_spec sample_spec; 103static pa_channel_map channel_map; 104static size_t sample_length = 0; 105#endif 106 107/* This variable tracks the number of ongoing asynchronous operations. When a 108 * new operation begins, this is incremented simply with actions++, and when 109 * an operation finishes, this is decremented with the complete_action() 110 * function, which shuts down the program if actions reaches zero. */ 111static int actions = 0; 112 113static bool nl = false; 114static pa_json_encoder *list_encoder = NULL; 115static pa_json_encoder *json_encoder = NULL; 116 117static enum { 118 NONE, 119 EXIT, 120 STAT, 121 INFO, 122 UPLOAD_SAMPLE, 123 PLAY_SAMPLE, 124 REMOVE_SAMPLE, 125 LIST, 126 MOVE_SINK_INPUT, 127 MOVE_SOURCE_OUTPUT, 128 LOAD_MODULE, 129 UNLOAD_MODULE, 130 SUSPEND_SINK, 131 SUSPEND_SOURCE, 132 SET_CARD_PROFILE, 133 SET_SINK_PORT, 134 GET_DEFAULT_SINK, 135 SET_DEFAULT_SINK, 136 SET_SOURCE_PORT, 137 GET_DEFAULT_SOURCE, 138 SET_DEFAULT_SOURCE, 139 GET_SINK_VOLUME, 140 SET_SINK_VOLUME, 141 GET_SOURCE_VOLUME, 142 SET_SOURCE_VOLUME, 143 SET_SINK_INPUT_VOLUME, 144 SET_SOURCE_OUTPUT_VOLUME, 145 GET_SINK_MUTE, 146 SET_SINK_MUTE, 147 GET_SOURCE_MUTE, 148 SET_SOURCE_MUTE, 149 SET_SINK_INPUT_MUTE, 150 SET_SOURCE_OUTPUT_MUTE, 151 SET_SINK_FORMATS, 152 SET_PORT_LATENCY_OFFSET, 153 SEND_MESSAGE, 154 SUBSCRIBE 155} action = NONE; 156 157static enum { 158 TEXT, 159 JSON 160} format = TEXT; 161 162static void quit(int ret) { 163 pa_assert(mainloop_api); 164 mainloop_api->quit(mainloop_api, ret); 165} 166 167static void context_drain_complete(pa_context *c, void *userdata) { 168 pa_context_disconnect(c); 169} 170 171static void drain(void) { 172 pa_operation *o; 173 174 if (!(o = pa_context_drain(context, context_drain_complete, NULL))) 175 pa_context_disconnect(context); 176 else 177 pa_operation_unref(o); 178} 179 180static void complete_action(void) { 181 pa_assert(actions > 0); 182 183 if (!(--actions)) 184 drain(); 185} 186 187static void stat_callback(pa_context *c, const pa_stat_info *i, void *userdata) { 188 char s[PA_BYTES_SNPRINT_MAX]; 189 if (!i) { 190 pa_log(_("Failed to get statistics: %s"), pa_strerror(pa_context_errno(c))); 191 quit(1); 192 return; 193 } 194 195 if (format == JSON) { 196 printf("{\"current\":{\"blocks\":%u,\"size\":%u}," 197 "\"lifetime\":{\"blocks\":%u,\"size\":%u}," 198 "\"sample_cache_size\":%u}", 199 i->memblock_total, 200 i->memblock_total_size, 201 i->memblock_allocated, 202 i->memblock_allocated_size, 203 i->scache_size); 204 } else { 205 pa_bytes_snprint(s, sizeof(s), i->memblock_total_size); 206 printf(ngettext("Currently in use: %u block containing %s bytes total.\n", 207 "Currently in use: %u blocks containing %s bytes total.\n", 208 i->memblock_total), 209 i->memblock_total, s); 210 211 pa_bytes_snprint(s, sizeof(s), i->memblock_allocated_size); 212 printf(ngettext("Allocated during whole lifetime: %u block containing %s bytes total.\n", 213 "Allocated during whole lifetime: %u blocks containing %s bytes total.\n", 214 i->memblock_allocated), 215 i->memblock_allocated, s); 216 217 pa_bytes_snprint(s, sizeof(s), i->scache_size); 218 printf(_("Sample cache size: %s\n"), s); 219 } 220 221 complete_action(); 222} 223 224static void get_default_sink(pa_context *c, const pa_server_info *i, void *userdata) { 225 if (!i) { 226 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c))); 227 quit(1); 228 return; 229 } 230 231 printf(_("%s\n"), i->default_sink_name); 232 233 complete_action(); 234} 235 236static void get_default_source(pa_context *c, const pa_server_info *i, void *userdata) { 237 if (!i) { 238 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c))); 239 quit(1); 240 return; 241 } 242 243 printf(_("%s\n"), i->default_source_name); 244 245 complete_action(); 246} 247 248static void get_server_info_callback(pa_context *c, const pa_server_info *i, void *useerdata) { 249 char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; 250 251 if (!i) { 252 pa_log(_("Failed to get server information: %s"), pa_strerror(pa_context_errno(c))); 253 quit(1); 254 return; 255 } 256 257 pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); 258 pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map); 259 260 if (format == JSON) { 261 char* tile_size = pa_sprintf_malloc("%zu", pa_context_get_tile_size(c, NULL)); 262 char* cookie = pa_sprintf_malloc("%04x:%04x", i->cookie >> 16, i->cookie & 0xFFFFU); 263 pa_json_encoder *encoder = pa_json_encoder_new(); 264 pa_json_encoder_begin_element_object(encoder); 265 pa_json_encoder_add_member_string(encoder, "server_string", pa_context_get_server(c)); 266 pa_json_encoder_add_member_int(encoder, "library_protocol_version", pa_context_get_protocol_version(c)); 267 pa_json_encoder_add_member_int(encoder, "server_protocol_version", pa_context_get_server_protocol_version(c)); 268 pa_json_encoder_add_member_string(encoder, "is_local", pa_yes_no_localised(pa_context_is_local(c))); 269 pa_json_encoder_add_member_int(encoder, "client_index", pa_context_get_index(c)); 270 pa_json_encoder_add_member_string(encoder, "tile_size", tile_size); 271 pa_json_encoder_add_member_string(encoder, "user_name", i->user_name); 272 pa_json_encoder_add_member_string(encoder, "host_name", i->host_name); 273 pa_json_encoder_add_member_string(encoder, "server_name", i->server_name); 274 pa_json_encoder_add_member_string(encoder, "server_version", i->server_version); 275 pa_json_encoder_add_member_string(encoder, "default_sample_specification", ss); 276 pa_json_encoder_add_member_string(encoder, "default_channel_map", cm); 277 pa_json_encoder_add_member_string(encoder, "default_sink_name", i->default_sink_name); 278 pa_json_encoder_add_member_string(encoder, "default_source_name", i->default_source_name); 279 pa_json_encoder_add_member_string(encoder, "cookie", cookie); 280 pa_json_encoder_end_object(encoder); 281 282 char* json_str = pa_json_encoder_to_string_free(encoder); 283 printf("%s", json_str); 284 pa_xfree(json_str); 285 pa_xfree(tile_size); 286 pa_xfree(cookie); 287 } else { 288 printf(_("Server String: %s\n" 289 "Library Protocol Version: %u\n" 290 "Server Protocol Version: %u\n" 291 "Is Local: %s\n" 292 "Client Index: %u\n" 293 "Tile Size: %zu\n"), 294 pa_context_get_server(c), 295 pa_context_get_protocol_version(c), 296 pa_context_get_server_protocol_version(c), 297 pa_yes_no_localised(pa_context_is_local(c)), 298 pa_context_get_index(c), 299 pa_context_get_tile_size(c, NULL)); 300 301 printf(_("User Name: %s\n" 302 "Host Name: %s\n" 303 "Server Name: %s\n" 304 "Server Version: %s\n" 305 "Default Sample Specification: %s\n" 306 "Default Channel Map: %s\n" 307 "Default Sink: %s\n" 308 "Default Source: %s\n" 309 "Cookie: %04x:%04x\n"), 310 i->user_name, 311 i->host_name, 312 i->server_name, 313 i->server_version, 314 ss, 315 cm, 316 i->default_sink_name, 317 i->default_source_name, 318 i->cookie >> 16, 319 i->cookie & 0xFFFFU); 320 } 321 322 complete_action(); 323} 324 325static const char* get_available_str(int available) { 326 switch (available) { 327 case PA_PORT_AVAILABLE_UNKNOWN: return _("availability unknown"); 328 case PA_PORT_AVAILABLE_YES: return _("available"); 329 case PA_PORT_AVAILABLE_NO: return _("not available"); 330 } 331 332 pa_assert_not_reached(); 333} 334 335static const char* get_device_port_type(unsigned int type) { 336 static char buf[32]; 337 switch (type) { 338 case PA_DEVICE_PORT_TYPE_UNKNOWN: return _("Unknown"); 339 case PA_DEVICE_PORT_TYPE_AUX: return _("Aux"); 340 case PA_DEVICE_PORT_TYPE_SPEAKER: return _("Speaker"); 341 case PA_DEVICE_PORT_TYPE_HEADPHONES: return _("Headphones"); 342 case PA_DEVICE_PORT_TYPE_LINE: return _("Line"); 343 case PA_DEVICE_PORT_TYPE_MIC: return _("Mic"); 344 case PA_DEVICE_PORT_TYPE_HEADSET: return _("Headset"); 345 case PA_DEVICE_PORT_TYPE_HANDSET: return _("Handset"); 346 case PA_DEVICE_PORT_TYPE_EARPIECE: return _("Earpiece"); 347 case PA_DEVICE_PORT_TYPE_SPDIF: return _("SPDIF"); 348 case PA_DEVICE_PORT_TYPE_HDMI: return _("HDMI"); 349 case PA_DEVICE_PORT_TYPE_TV: return _("TV"); 350 case PA_DEVICE_PORT_TYPE_RADIO: return _("Radio"); 351 case PA_DEVICE_PORT_TYPE_VIDEO: return _("Video"); 352 case PA_DEVICE_PORT_TYPE_USB: return _("USB"); 353 case PA_DEVICE_PORT_TYPE_BLUETOOTH: return _("Bluetooth"); 354 case PA_DEVICE_PORT_TYPE_PORTABLE: return _("Portable"); 355 case PA_DEVICE_PORT_TYPE_HANDSFREE: return _("Handsfree"); 356 case PA_DEVICE_PORT_TYPE_CAR: return _("Car"); 357 case PA_DEVICE_PORT_TYPE_HIFI: return _("HiFi"); 358 case PA_DEVICE_PORT_TYPE_PHONE: return _("Phone"); 359 case PA_DEVICE_PORT_TYPE_NETWORK: return _("Network"); 360 case PA_DEVICE_PORT_TYPE_ANALOG: return _("Analog"); 361 } 362 snprintf(buf, sizeof(buf), "%s-%u", _("Unknown"), type); 363 return buf; 364} 365 366char* pa_proplist_to_json_object(const pa_proplist *p) { 367 const char *key; 368 void *state = NULL; 369 pa_json_encoder *encoder; 370 371 pa_assert(p); 372 373 encoder = pa_json_encoder_new(); 374 pa_json_encoder_begin_element_object(encoder); 375 while (true) { 376 key = pa_proplist_iterate(p, &state); 377 if (!key) break; 378 379 const char *v; 380 381 if ((v = pa_proplist_gets(p, key))) { 382 pa_json_encoder_add_member_string(encoder, key, v); 383 } else { 384 const void *value; 385 size_t nbytes; 386 char *c; 387 char* hex_str; 388 389 pa_assert_se(pa_proplist_get(p, key, &value, &nbytes) == 0); 390 c = pa_xmalloc(nbytes*2+1); 391 pa_hexstr((const uint8_t*) value, nbytes, c, nbytes*2+1); 392 393 hex_str = pa_sprintf_malloc("hex:%s", c); 394 pa_json_encoder_add_member_string(encoder, key, hex_str); 395 pa_xfree(c); 396 pa_xfree(hex_str); 397 } 398 } 399 pa_json_encoder_end_object(encoder); 400 401 return pa_json_encoder_to_string_free(encoder); 402} 403 404static const char* pa_sink_ports_to_json_array(pa_sink_port_info **ports) { 405 pa_json_encoder *encoder = pa_json_encoder_new(); 406 if (!ports) { 407 pa_json_encoder_begin_element_array(encoder); 408 pa_json_encoder_end_array(encoder); 409 return pa_json_encoder_to_string_free(encoder); 410 } 411 412 pa_sink_port_info **p; 413 414 pa_json_encoder_begin_element_array(encoder); 415 for (p = ports; *p; p++) { 416 pa_json_encoder *sink_port_encoder = pa_json_encoder_new(); 417 pa_json_encoder_begin_element_object(sink_port_encoder); 418 pa_json_encoder_add_member_string(sink_port_encoder, "name", (*p)->name); 419 pa_json_encoder_add_member_string(sink_port_encoder, "description", (*p)->description); 420 pa_json_encoder_add_member_string(sink_port_encoder, "type", get_device_port_type((*p)->type)); 421 pa_json_encoder_add_member_int(sink_port_encoder, "priority", (*p)->priority); 422 pa_json_encoder_add_member_string(sink_port_encoder, "availability_group", (*p)->availability_group); 423 pa_json_encoder_add_member_string(sink_port_encoder, "availability", get_available_str((*p)->available)); 424 pa_json_encoder_end_object(sink_port_encoder); 425 426 char* sink_port_str = pa_json_encoder_to_string_free(sink_port_encoder); 427 pa_json_encoder_add_element_raw_json(encoder, sink_port_str); 428 pa_xfree(sink_port_str); 429 } 430 pa_json_encoder_end_array(encoder); 431 432 return pa_json_encoder_to_string_free(encoder); 433} 434 435static const char* pa_source_ports_to_json_array(pa_source_port_info **ports) { 436 pa_json_encoder *encoder = pa_json_encoder_new(); 437 if (!ports) { 438 pa_json_encoder_begin_element_array(encoder); 439 pa_json_encoder_end_array(encoder); 440 return pa_json_encoder_to_string_free(encoder); 441 } 442 443 pa_source_port_info **p; 444 445 pa_json_encoder_begin_element_array(encoder); 446 for (p = ports; *p; p++) { 447 pa_json_encoder *source_port_encoder = pa_json_encoder_new(); 448 pa_json_encoder_begin_element_object(source_port_encoder); 449 pa_json_encoder_add_member_string(source_port_encoder, "name", (*p)->name); 450 pa_json_encoder_add_member_string(source_port_encoder, "description", (*p)->description); 451 pa_json_encoder_add_member_string(source_port_encoder, "type", get_device_port_type((*p)->type)); 452 pa_json_encoder_add_member_int(source_port_encoder, "priority", (*p)->priority); 453 pa_json_encoder_add_member_string(source_port_encoder, "availability_group", (*p)->availability_group); 454 pa_json_encoder_add_member_string(source_port_encoder, "availability", get_available_str((*p)->available)); 455 pa_json_encoder_end_object(source_port_encoder); 456 457 char* source_port_str = pa_json_encoder_to_string_free(source_port_encoder); 458 pa_json_encoder_add_element_raw_json(encoder, source_port_str); 459 pa_xfree(source_port_str); 460 } 461 pa_json_encoder_end_array(encoder); 462 463 return pa_json_encoder_to_string_free(encoder); 464} 465 466static const char* pa_format_infos_to_json_array(pa_format_info **formats, uint8_t n_formats) { 467 pa_json_encoder *encoder = pa_json_encoder_new(); 468 if (!formats) { 469 pa_json_encoder_begin_element_array(encoder); 470 pa_json_encoder_end_array(encoder); 471 return pa_json_encoder_to_string_free(encoder); 472 } 473 474 char f[PA_FORMAT_INFO_SNPRINT_MAX]; 475 uint8_t i; 476 477 pa_json_encoder_begin_element_array(encoder); 478 for (i = 0; i < n_formats; i++) { 479 pa_json_encoder_add_element_string(encoder, pa_format_info_snprint(f, sizeof(f), formats[i])); 480 } 481 pa_json_encoder_end_array(encoder); 482 483 return pa_json_encoder_to_string_free(encoder); 484} 485 486const char* pa_volume_to_json_object(pa_volume_t v, int print_dB) { 487 pa_json_encoder *encoder = pa_json_encoder_new(); 488 if (!PA_VOLUME_IS_VALID(v)) { 489 pa_json_encoder_begin_element_object(encoder); 490 pa_json_encoder_add_member_string(encoder, "error", _("(invalid)")); 491 pa_json_encoder_end_object(encoder); 492 return pa_json_encoder_to_string_free(encoder); 493 } 494 495 char dB[PA_SW_VOLUME_SNPRINT_DB_MAX]; 496 char* value_percent = pa_sprintf_malloc("%u%%", (unsigned)(((uint64_t)v * 100 + (uint64_t)PA_VOLUME_NORM / 2) / (uint64_t)PA_VOLUME_NORM)); 497 pa_json_encoder_begin_element_object(encoder); 498 pa_json_encoder_add_member_int(encoder, "value", v); 499 pa_json_encoder_add_member_string(encoder, "value_percent", value_percent); 500 pa_json_encoder_add_member_string(encoder, "db", print_dB ? pa_sw_volume_snprint_dB(dB, sizeof(dB), v) : NULL); 501 pa_json_encoder_end_object(encoder); 502 pa_xfree(value_percent); 503 504 return pa_json_encoder_to_string_free(encoder); 505} 506 507const char* pa_cvolume_to_json_object(const pa_cvolume *c, const pa_channel_map *map, int print_dB) { 508 pa_json_encoder *encoder = pa_json_encoder_new(); 509 if (!pa_cvolume_valid(c)) { 510 pa_json_encoder_begin_element_object(encoder); 511 pa_json_encoder_add_member_string(encoder, "error", _("(invalid)")); 512 pa_json_encoder_end_object(encoder); 513 return pa_json_encoder_to_string_free(encoder); 514 } 515 516 pa_assert(!map || (map->channels == c->channels)); 517 pa_assert(!map || pa_channel_map_valid(map)); 518 519 pa_json_encoder_begin_element_object(encoder); 520 for (unsigned channel = 0; channel < c->channels; channel++) { 521 char channel_position[32]; 522 if (map) 523 pa_snprintf(channel_position, sizeof(channel_position), "%s", pa_channel_position_to_string(map->map[channel])); 524 else 525 pa_snprintf(channel_position, sizeof(channel_position), "%u", channel); 526 527 pa_json_encoder_add_member_raw_json(encoder, 528 channel_position, 529 pa_volume_to_json_object(c->values[channel], print_dB)); 530 } 531 pa_json_encoder_end_object(encoder); 532 533 return pa_json_encoder_to_string_free(encoder); 534} 535 536static void pa_json_encoder_end_array_handler(const char *name) { 537 pa_assert(json_encoder != NULL); 538 539 pa_json_encoder_end_array(json_encoder); 540 char* json_str = pa_json_encoder_to_string_free(json_encoder); 541 if (list_encoder != NULL) { 542 pa_json_encoder_add_member_raw_json(list_encoder, name, json_str); 543 } else { 544 printf("%s", json_str); 545 } 546 pa_xfree(json_str); 547 548 json_encoder = NULL; 549} 550 551static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { 552 553 static const char *state_table[] = { 554 [1+PA_SINK_INVALID_STATE] = "n/a", 555 [1+PA_SINK_RUNNING] = "RUNNING", 556 [1+PA_SINK_IDLE] = "IDLE", 557 [1+PA_SINK_SUSPENDED] = "SUSPENDED" 558 }; 559 560 char 561 s[PA_SAMPLE_SPEC_SNPRINT_MAX], 562 cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], 563 v[PA_VOLUME_SNPRINT_VERBOSE_MAX], 564 cm[PA_CHANNEL_MAP_SNPRINT_MAX], 565 f[PA_FORMAT_INFO_SNPRINT_MAX]; 566 char *pl; 567 568 if (format == JSON && json_encoder == NULL) { 569 json_encoder = pa_json_encoder_new(); 570 pa_json_encoder_begin_element_array(json_encoder); 571 } 572 573 if (is_last < 0) { 574 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c))); 575 quit(1); 576 return; 577 } 578 579 if (is_last) { 580 if (format == JSON) { 581 pa_json_encoder_end_array_handler("sinks"); 582 } 583 complete_action(); 584 return; 585 } 586 587 pa_assert(i); 588 589 if (nl && !short_list_format && format == TEXT) 590 printf("\n"); 591 nl = true; 592 593 char *sample_spec = pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); 594 if (short_list_format) { 595 if (format == JSON) { 596 pa_json_encoder *encoder = pa_json_encoder_new(); 597 pa_json_encoder_begin_element_object(encoder); 598 pa_json_encoder_add_member_int(encoder, "index", i->index); 599 pa_json_encoder_add_member_string(encoder, "name", i->name); 600 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 601 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 602 pa_json_encoder_add_member_string(encoder, "state", state_table[1+i->state]); 603 pa_json_encoder_end_object(encoder); 604 605 char* json_str = pa_json_encoder_to_string_free(encoder); 606 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 607 pa_xfree(json_str); 608 } else { 609 printf("%u\t%s\t%s\t%s\t%s\n", 610 i->index, 611 i->name, 612 pa_strnull(i->driver), 613 sample_spec, 614 state_table[1+i->state]); 615 } 616 return; 617 } 618 619 char *channel_map = pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map); 620 float volume_balance = pa_cvolume_get_balance(&i->volume, &i->channel_map); 621 622 if (format == JSON) { 623 pa_json_encoder *latency_encoder = pa_json_encoder_new(); 624 pa_json_encoder_begin_element_object(latency_encoder); 625 pa_json_encoder_add_member_double(latency_encoder, "actual", (double) i->latency, 2); 626 pa_json_encoder_add_member_double(latency_encoder, "configured", (double) i->configured_latency, 2); 627 pa_json_encoder_end_object(latency_encoder); 628 char* latency_json_str = pa_json_encoder_to_string_free(latency_encoder); 629 630 pa_json_encoder *flags_encoder = pa_json_encoder_new(); 631 pa_json_encoder_begin_element_array(flags_encoder); 632 if (i->flags & PA_SINK_HARDWARE) pa_json_encoder_add_element_string(flags_encoder, "HARDWARE"); 633 if (i->flags & PA_SINK_NETWORK) pa_json_encoder_add_element_string(flags_encoder, "NETWORK"); 634 if (i->flags & PA_SINK_HW_MUTE_CTRL) pa_json_encoder_add_element_string(flags_encoder, "HW_MUTE_CTRL"); 635 if (i->flags & PA_SINK_HW_VOLUME_CTRL) pa_json_encoder_add_element_string(flags_encoder, "HW_VOLUME_CTRL"); 636 if (i->flags & PA_SINK_DECIBEL_VOLUME) pa_json_encoder_add_element_string(flags_encoder, "DECIBEL_VOLUME"); 637 if (i->flags & PA_SINK_LATENCY) pa_json_encoder_add_element_string(flags_encoder, "LATENCY"); 638 if (i->flags & PA_SINK_SET_FORMATS) pa_json_encoder_add_element_string(flags_encoder, "SET_FORMATS"); 639 pa_json_encoder_end_array(flags_encoder); 640 char* flags_json_str = pa_json_encoder_to_string_free(flags_encoder); 641 642 pa_json_encoder *encoder = pa_json_encoder_new(); 643 pa_json_encoder_begin_element_object(encoder); 644 pa_json_encoder_add_member_int(encoder, "index", i->index); 645 pa_json_encoder_add_member_string(encoder, "state", state_table[1+i->state]); 646 pa_json_encoder_add_member_string(encoder, "name", i->name); 647 pa_json_encoder_add_member_string(encoder, "description", i->description); 648 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 649 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 650 pa_json_encoder_add_member_string(encoder, "channel_map", channel_map); 651 pa_json_encoder_add_member_int(encoder, "owner_module", i->owner_module); 652 pa_json_encoder_add_member_bool(encoder, "mute", i->mute); 653 pa_json_encoder_add_member_raw_json(encoder, "volume", pa_cvolume_to_json_object(&i->volume, &i->channel_map, i->flags & PA_SINK_DECIBEL_VOLUME)); 654 pa_json_encoder_add_member_double(encoder, "balance", volume_balance, 2); 655 pa_json_encoder_add_member_raw_json(encoder, "base_volume", pa_volume_to_json_object(i->base_volume, i->flags & PA_SINK_DECIBEL_VOLUME)); 656 pa_json_encoder_add_member_string(encoder, "monitor_source", i->monitor_source_name); 657 pa_json_encoder_add_member_raw_json(encoder, "latency", latency_json_str); 658 pa_json_encoder_add_member_raw_json(encoder, "flags", flags_json_str); 659 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 660 pa_json_encoder_add_member_raw_json(encoder, "ports", pa_sink_ports_to_json_array(i->ports)); 661 i->active_port ? pa_json_encoder_add_member_string(encoder, "active_port", i->active_port->name): pa_json_encoder_add_member_null(encoder, "active_port"); 662 pa_json_encoder_add_member_raw_json(encoder, "formats", pa_format_infos_to_json_array(i->formats, i->n_formats)); 663 pa_json_encoder_end_object(encoder); 664 665 char* json_str = pa_json_encoder_to_string_free(encoder); 666 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 667 pa_xfree(json_str); 668 pa_xfree(latency_json_str); 669 pa_xfree(flags_json_str); 670 } else { 671 printf(_("Sink #%u\n" 672 "\tState: %s\n" 673 "\tName: %s\n" 674 "\tDescription: %s\n" 675 "\tDriver: %s\n" 676 "\tSample Specification: %s\n" 677 "\tChannel Map: %s\n" 678 "\tOwner Module: %u\n" 679 "\tMute: %s\n" 680 "\tVolume: %s\n" 681 "\t balance %0.2f\n" 682 "\tBase Volume: %s\n" 683 "\tMonitor Source: %s\n" 684 "\tLatency: %0.0f usec, configured %0.0f usec\n" 685 "\tFlags: %s%s%s%s%s%s%s\n" 686 "\tProperties:\n\t\t%s\n"), 687 i->index, 688 state_table[1+i->state], 689 i->name, 690 pa_strnull(i->description), 691 pa_strnull(i->driver), 692 sample_spec, 693 channel_map, 694 i->owner_module, 695 pa_yes_no_localised(i->mute), 696 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SINK_DECIBEL_VOLUME), 697 volume_balance, 698 pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SINK_DECIBEL_VOLUME), 699 pa_strnull(i->monitor_source_name), 700 (double) i->latency, (double) i->configured_latency, 701 i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "", 702 i->flags & PA_SINK_NETWORK ? "NETWORK " : "", 703 i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "", 704 i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", 705 i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "", 706 i->flags & PA_SINK_LATENCY ? "LATENCY " : "", 707 i->flags & PA_SINK_SET_FORMATS ? "SET_FORMATS " : "", 708 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 709 710 if (i->ports) { 711 pa_sink_port_info **p; 712 713 printf(_("\tPorts:\n")); 714 for (p = i->ports; *p; p++) 715 printf(_("\t\t%s: %s (type: %s, priority: %u%s%s, %s)\n"), 716 (*p)->name, (*p)->description, get_device_port_type((*p)->type), 717 (*p)->priority, (*p)->availability_group ? _(", availability group: ") : "", 718 (*p)->availability_group ?: "", get_available_str((*p)->available)); 719 } 720 721 if (i->active_port) 722 printf(_("\tActive Port: %s\n"), 723 i->active_port->name); 724 725 if (i->formats) { 726 uint8_t j; 727 728 printf(_("\tFormats:\n")); 729 for (j = 0; j < i->n_formats; j++) 730 printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j])); 731 } 732 } 733 734 pa_xfree(pl); 735} 736 737static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { 738 739 static const char *state_table[] = { 740 [1+PA_SOURCE_INVALID_STATE] = "n/a", 741 [1+PA_SOURCE_RUNNING] = "RUNNING", 742 [1+PA_SOURCE_IDLE] = "IDLE", 743 [1+PA_SOURCE_SUSPENDED] = "SUSPENDED" 744 }; 745 746 char 747 s[PA_SAMPLE_SPEC_SNPRINT_MAX], 748 cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], 749 v[PA_VOLUME_SNPRINT_VERBOSE_MAX], 750 cm[PA_CHANNEL_MAP_SNPRINT_MAX], 751 f[PA_FORMAT_INFO_SNPRINT_MAX]; 752 char *pl; 753 754 if (format == JSON && json_encoder == NULL) { 755 json_encoder = pa_json_encoder_new(); 756 pa_json_encoder_begin_element_array(json_encoder); 757 } 758 759 if (is_last < 0) { 760 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c))); 761 quit(1); 762 return; 763 } 764 765 if (is_last) { 766 if (format == JSON) { 767 pa_json_encoder_end_array_handler("sources"); 768 } 769 complete_action(); 770 return; 771 } 772 773 pa_assert(i); 774 775 if (nl && !short_list_format && format == TEXT) 776 printf("\n"); 777 nl = true; 778 779 char *sample_spec = pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); 780 if (short_list_format) { 781 if (format == JSON) { 782 pa_json_encoder *encoder = pa_json_encoder_new(); 783 pa_json_encoder_begin_element_object(encoder); 784 pa_json_encoder_add_member_int(encoder, "index", i->index); 785 pa_json_encoder_add_member_string(encoder, "name", i->name); 786 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 787 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 788 pa_json_encoder_add_member_string(encoder, "state", state_table[1+i->state]); 789 pa_json_encoder_end_object(encoder); 790 791 char* json_str = pa_json_encoder_to_string_free(encoder); 792 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 793 pa_xfree(json_str); 794 } else { 795 printf("%u\t%s\t%s\t%s\t%s\n", 796 i->index, 797 i->name, 798 pa_strnull(i->driver), 799 sample_spec, 800 state_table[1+i->state]); 801 } 802 return; 803 } 804 805 char *channel_map = pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map); 806 float volume_balance = pa_cvolume_get_balance(&i->volume, &i->channel_map); 807 808 if (format == JSON) { 809 pa_json_encoder *latency_encoder = pa_json_encoder_new(); 810 pa_json_encoder_begin_element_object(latency_encoder); 811 pa_json_encoder_add_member_double(latency_encoder, "actual", (double) i->latency, 2); 812 pa_json_encoder_add_member_double(latency_encoder, "configured", (double) i->configured_latency, 2); 813 pa_json_encoder_end_object(latency_encoder); 814 char* latency_json_str = pa_json_encoder_to_string_free(latency_encoder); 815 816 pa_json_encoder *flags_encoder = pa_json_encoder_new(); 817 pa_json_encoder_begin_element_array(flags_encoder); 818 if (i->flags & PA_SOURCE_HARDWARE) pa_json_encoder_add_element_string(flags_encoder, "HARDWARE"); 819 if (i->flags & PA_SOURCE_NETWORK) pa_json_encoder_add_element_string(flags_encoder, "NETWORK"); 820 if (i->flags & PA_SOURCE_HW_MUTE_CTRL) pa_json_encoder_add_element_string(flags_encoder, "HW_MUTE_CTRL"); 821 if (i->flags & PA_SOURCE_HW_VOLUME_CTRL) pa_json_encoder_add_element_string(flags_encoder, "HW_VOLUME_CTRL"); 822 if (i->flags & PA_SOURCE_DECIBEL_VOLUME) pa_json_encoder_add_element_string(flags_encoder, "DECIBEL_VOLUME"); 823 if (i->flags & PA_SOURCE_LATENCY) pa_json_encoder_add_element_string(flags_encoder, "LATENCY"); 824 pa_json_encoder_end_array(flags_encoder); 825 char* flags_json_str = pa_json_encoder_to_string_free(flags_encoder); 826 827 pa_json_encoder *encoder = pa_json_encoder_new(); 828 pa_json_encoder_begin_element_object(encoder); 829 pa_json_encoder_add_member_int(encoder, "index", i->index); 830 pa_json_encoder_add_member_string(encoder, "state", state_table[1+i->state]); 831 pa_json_encoder_add_member_string(encoder, "name", i->name); 832 pa_json_encoder_add_member_string(encoder, "description", i->description); 833 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 834 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 835 pa_json_encoder_add_member_string(encoder, "channel_map", channel_map); 836 pa_json_encoder_add_member_int(encoder, "owner_module", i->owner_module); 837 pa_json_encoder_add_member_bool(encoder, "mute", i->mute); 838 pa_json_encoder_add_member_raw_json(encoder, "volume", pa_cvolume_to_json_object(&i->volume, &i->channel_map, i->flags & PA_SINK_DECIBEL_VOLUME)); 839 pa_json_encoder_add_member_double(encoder, "balance", volume_balance, 2); 840 pa_json_encoder_add_member_raw_json(encoder, "base_volume", pa_volume_to_json_object(i->base_volume, i->flags & PA_SINK_DECIBEL_VOLUME)); 841 pa_json_encoder_add_member_string(encoder, "monitor_source", i->monitor_of_sink_name); 842 pa_json_encoder_add_member_raw_json(encoder, "latency", latency_json_str); 843 pa_json_encoder_add_member_raw_json(encoder, "flags", flags_json_str); 844 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 845 pa_json_encoder_add_member_raw_json(encoder, "ports", pa_source_ports_to_json_array(i->ports)); 846 i->active_port ? pa_json_encoder_add_member_string(encoder, "active_port", i->active_port->name) : pa_json_encoder_add_member_null(encoder, "active_port"); 847 pa_json_encoder_add_member_raw_json(encoder, "formats", pa_format_infos_to_json_array(i->formats, i->n_formats)); 848 pa_json_encoder_end_object(encoder); 849 850 char* json_str = pa_json_encoder_to_string_free(encoder); 851 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 852 pa_xfree(json_str); 853 pa_xfree(latency_json_str); 854 pa_xfree(flags_json_str); 855 } else { 856 printf(_("Source #%u\n" 857 "\tState: %s\n" 858 "\tName: %s\n" 859 "\tDescription: %s\n" 860 "\tDriver: %s\n" 861 "\tSample Specification: %s\n" 862 "\tChannel Map: %s\n" 863 "\tOwner Module: %u\n" 864 "\tMute: %s\n" 865 "\tVolume: %s\n" 866 "\t balance %0.2f\n" 867 "\tBase Volume: %s\n" 868 "\tMonitor of Sink: %s\n" 869 "\tLatency: %0.0f usec, configured %0.0f usec\n" 870 "\tFlags: %s%s%s%s%s%s\n" 871 "\tProperties:\n\t\t%s\n"), 872 i->index, 873 state_table[1+i->state], 874 i->name, 875 pa_strnull(i->description), 876 pa_strnull(i->driver), 877 sample_spec, 878 channel_map, 879 i->owner_module, 880 pa_yes_no_localised(i->mute), 881 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, i->flags & PA_SOURCE_DECIBEL_VOLUME), 882 volume_balance, 883 pa_volume_snprint_verbose(v, sizeof(v), i->base_volume, i->flags & PA_SOURCE_DECIBEL_VOLUME), 884 i->monitor_of_sink_name ? i->monitor_of_sink_name : _("n/a"), 885 (double) i->latency, (double) i->configured_latency, 886 i->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "", 887 i->flags & PA_SOURCE_NETWORK ? "NETWORK " : "", 888 i->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "", 889 i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", 890 i->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "", 891 i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", 892 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 893 894 if (i->ports) { 895 pa_source_port_info **p; 896 897 printf(_("\tPorts:\n")); 898 for (p = i->ports; *p; p++) 899 printf(_("\t\t%s: %s (type: %s, priority: %u%s%s, %s)\n"), 900 (*p)->name, (*p)->description, get_device_port_type((*p)->type), 901 (*p)->priority, (*p)->availability_group ? _(", availability group: ") : "", 902 (*p)->availability_group ?: "", get_available_str((*p)->available)); 903 } 904 905 if (i->active_port) 906 printf(_("\tActive Port: %s\n"), 907 i->active_port->name); 908 909 if (i->formats) { 910 uint8_t j; 911 912 printf(_("\tFormats:\n")); 913 for (j = 0; j < i->n_formats; j++) 914 printf("\t\t%s\n", pa_format_info_snprint(f, sizeof(f), i->formats[j])); 915 } 916 } 917 918 pa_xfree(pl); 919} 920 921static void get_module_info_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) { 922 char t[32]; 923 char *pl; 924 925 if (format == JSON && json_encoder == NULL) { 926 json_encoder = pa_json_encoder_new(); 927 pa_json_encoder_begin_element_array(json_encoder); 928 } 929 930 if (is_last < 0) { 931 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c))); 932 quit(1); 933 return; 934 } 935 936 if (is_last) { 937 if (format == JSON) { 938 pa_json_encoder_end_array_handler("modules"); 939 } 940 complete_action(); 941 return; 942 } 943 944 pa_assert(i); 945 946 if (nl && !short_list_format && format == TEXT) 947 printf("\n"); 948 nl = true; 949 950 pa_snprintf(t, sizeof(t), "%u", i->n_used); 951 952 if (short_list_format) { 953 if (format == JSON) { 954 pa_json_encoder *encoder = pa_json_encoder_new(); 955 pa_json_encoder_begin_element_object(encoder); 956 pa_json_encoder_add_member_string(encoder, "name", i->name); 957 pa_json_encoder_add_member_string(encoder, "argument", i->argument); 958 pa_json_encoder_end_object(encoder); 959 960 char* json_str = pa_json_encoder_to_string_free(encoder); 961 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 962 pa_xfree(json_str); 963 } else { 964 printf("%u\t%s\t%s\t\n", i->index, i->name, i->argument ? i->argument : ""); 965 } 966 return; 967 } 968 969 char *n_used = i->n_used != PA_INVALID_INDEX ? t : _("n/a"); 970 if (format == JSON) { 971 pa_json_encoder *encoder = pa_json_encoder_new(); 972 pa_json_encoder_begin_element_object(encoder); 973 pa_json_encoder_add_member_string(encoder, "name", i->name); 974 pa_json_encoder_add_member_string(encoder, "argument", i->argument); 975 pa_json_encoder_add_member_string(encoder, "usage_counter", n_used); 976 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 977 pa_json_encoder_end_object(encoder); 978 979 char* json_str = pa_json_encoder_to_string_free(encoder); 980 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 981 pa_xfree(json_str); 982 } else { 983 printf(_("Module #%u\n" 984 "\tName: %s\n" 985 "\tArgument: %s\n" 986 "\tUsage counter: %s\n" 987 "\tProperties:\n\t\t%s\n"), 988 i->index, 989 i->name, 990 i->argument ? i->argument : "", 991 n_used, 992 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 993 994 } 995 996 pa_xfree(pl); 997} 998 999static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) { 1000 char t[32]; 1001 char *pl; 1002 1003 if (format == JSON && json_encoder == NULL) { 1004 json_encoder = pa_json_encoder_new(); 1005 pa_json_encoder_begin_element_array(json_encoder); 1006 } 1007 1008 if (is_last < 0) { 1009 pa_log(_("Failed to get client information: %s"), pa_strerror(pa_context_errno(c))); 1010 quit(1); 1011 return; 1012 } 1013 1014 if (is_last) { 1015 if (format == JSON) { 1016 pa_json_encoder_end_array_handler("clients"); 1017 } 1018 complete_action(); 1019 return; 1020 } 1021 1022 pa_assert(i); 1023 1024 if (nl && !short_list_format && format == TEXT) 1025 printf("\n"); 1026 nl = true; 1027 1028 pa_snprintf(t, sizeof(t), "%u", i->owner_module); 1029 1030 if (short_list_format) { 1031 if (format == JSON) { 1032 pa_json_encoder *encoder = pa_json_encoder_new(); 1033 pa_json_encoder_begin_element_object(encoder); 1034 pa_json_encoder_add_member_int(encoder, "index", i->index); 1035 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 1036 pa_json_encoder_add_member_string(encoder, PA_PROP_APPLICATION_PROCESS_BINARY, pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); 1037 pa_json_encoder_end_object(encoder); 1038 1039 char* json_str = pa_json_encoder_to_string_free(encoder); 1040 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1041 pa_xfree(json_str); 1042 } else { 1043 printf("%u\t%s\t%s\n", 1044 i->index, 1045 pa_strnull(i->driver), 1046 pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_PROCESS_BINARY))); 1047 } 1048 return; 1049 } else { 1050 if (format == JSON) { 1051 pa_json_encoder *encoder = pa_json_encoder_new(); 1052 pa_json_encoder_begin_element_object(encoder); 1053 pa_json_encoder_add_member_int(encoder, "index", i->index); 1054 i->driver ? pa_json_encoder_add_member_string(encoder, "driver", i->driver) : pa_json_encoder_add_member_null(encoder, "driver"); 1055 i->owner_module != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "owner_module", t) : pa_json_encoder_add_member_null(encoder, "owner_module"); 1056 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 1057 pa_json_encoder_end_object(encoder); 1058 1059 char* json_str = pa_json_encoder_to_string_free(encoder); 1060 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1061 pa_xfree(json_str); 1062 } else { 1063 printf(_("Client #%u\n" 1064 "\tDriver: %s\n" 1065 "\tOwner Module: %s\n" 1066 "\tProperties:\n\t\t%s\n"), 1067 i->index, 1068 pa_strnull(i->driver), 1069 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"), 1070 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 1071 } 1072 } 1073 1074 pa_xfree(pl); 1075} 1076 1077const char* pa_card_profile_info_2_to_json_object(pa_card_profile_info2 **profiles2) { 1078 pa_json_encoder *encoder = pa_json_encoder_new(); 1079 if (!profiles2) { 1080 pa_json_encoder_begin_element_object(encoder); 1081 pa_json_encoder_end_object(encoder); 1082 return pa_json_encoder_to_string_free(encoder); 1083 } 1084 1085 pa_card_profile_info2 **p; 1086 1087 pa_json_encoder_begin_element_object(encoder); 1088 for (p = profiles2; *p; p++) { 1089 pa_json_encoder *info_json_2_encoder = pa_json_encoder_new(); 1090 pa_json_encoder_begin_element_object(info_json_2_encoder); 1091 pa_json_encoder_add_member_string(info_json_2_encoder, "description", (*p)->description); 1092 pa_json_encoder_add_member_int(info_json_2_encoder, "sinks", (*p)->n_sinks); 1093 pa_json_encoder_add_member_int(info_json_2_encoder, "sources", (*p)->n_sources); 1094 pa_json_encoder_add_member_int(info_json_2_encoder, "priority", (*p)->priority); 1095 pa_json_encoder_add_member_bool(info_json_2_encoder, "available", (*p)->available); 1096 pa_json_encoder_end_object(info_json_2_encoder); 1097 1098 char *info_json_2_str = pa_json_encoder_to_string_free(info_json_2_encoder); 1099 pa_json_encoder_add_member_raw_json(encoder, (*p)->name, info_json_2_str); 1100 pa_xfree(info_json_2_str); 1101 } 1102 pa_json_encoder_end_object(encoder); 1103 1104 return pa_json_encoder_to_string_free(encoder); 1105} 1106 1107const char* pa_card_profile_info_to_json_array(pa_card_profile_info **info) { 1108 pa_json_encoder *encoder = pa_json_encoder_new(); 1109 if (!info) { 1110 pa_json_encoder_begin_element_array(encoder); 1111 pa_json_encoder_end_array(encoder); 1112 return pa_json_encoder_to_string_free(encoder); 1113 } 1114 1115 pa_card_profile_info **p; 1116 1117 pa_json_encoder_begin_element_array(encoder); 1118 for (p = info; *p; p++) { 1119 pa_json_encoder_add_element_string(encoder, (*p)->name); 1120 } 1121 pa_json_encoder_end_array(encoder); 1122 1123 return pa_json_encoder_to_string_free(encoder); 1124} 1125 1126const char* pa_card_port_info_to_json_object(pa_card_port_info **info) { 1127 pa_json_encoder *encoder = pa_json_encoder_new(); 1128 if (!info) { 1129 pa_json_encoder_begin_element_object(encoder); 1130 pa_json_encoder_end_object(encoder); 1131 return pa_json_encoder_to_string_free(encoder); 1132 } 1133 1134 pa_card_port_info **p; 1135 char *pl; 1136 1137 pa_json_encoder_begin_element_object(encoder); 1138 for (p = info; *p; p++) { 1139 pa_card_profile_info **pr = (*p)->profiles; 1140 1141 char* latency_offset_str = pa_sprintf_malloc("%"PRId64" usec", (*p)->latency_offset); 1142 pa_json_encoder *port_info_encoder = pa_json_encoder_new(); 1143 pa_json_encoder_begin_element_object(port_info_encoder); 1144 pa_json_encoder_add_member_string(port_info_encoder, "description", (*p)->description); 1145 pa_json_encoder_add_member_string(port_info_encoder, "type", get_device_port_type((*p)->type)); 1146 pa_json_encoder_add_member_int(port_info_encoder, "priority", (*p)->priority); 1147 pa_json_encoder_add_member_string(port_info_encoder, "latency_offset", latency_offset_str); 1148 pa_json_encoder_add_member_string(port_info_encoder, "availability_group", (*p)->availability_group); 1149 pa_json_encoder_add_member_string(port_info_encoder, "availability", get_available_str((*p)->available)); 1150 pa_json_encoder_add_member_raw_json(port_info_encoder, "properties", pl = pa_proplist_to_json_object((*p)->proplist)); 1151 pa_json_encoder_add_member_raw_json(port_info_encoder, "profiles", pa_card_profile_info_to_json_array(pr)); 1152 pa_json_encoder_end_object(port_info_encoder); 1153 1154 char *port_info_str = pa_json_encoder_to_string_free(port_info_encoder); 1155 pa_json_encoder_add_member_raw_json(encoder, (*p)->name, port_info_str); 1156 pa_xfree(port_info_str); 1157 pa_xfree(latency_offset_str); 1158 pa_xfree(pl); 1159 } 1160 pa_json_encoder_end_object(encoder); 1161 1162 return pa_json_encoder_to_string_free(encoder); 1163} 1164 1165static void get_card_info_callback(pa_context *c, const pa_card_info *i, int is_last, void *userdata) { 1166 char t[32]; 1167 char *pl; 1168 1169 if (format == JSON && json_encoder == NULL) { 1170 json_encoder = pa_json_encoder_new(); 1171 pa_json_encoder_begin_element_array(json_encoder); 1172 } 1173 1174 if (is_last < 0) { 1175 pa_log(_("Failed to get card information: %s"), pa_strerror(pa_context_errno(c))); 1176 complete_action(); 1177 return; 1178 } 1179 1180 if (is_last) { 1181 if (format == JSON) { 1182 pa_json_encoder_end_array_handler("cards"); 1183 } 1184 complete_action(); 1185 return; 1186 } 1187 1188 pa_assert(i); 1189 1190 if (nl && !short_list_format && format == TEXT) 1191 printf("\n"); 1192 nl = true; 1193 1194 pa_snprintf(t, sizeof(t), "%u", i->owner_module); 1195 1196 if (short_list_format) { 1197 if (format == JSON) { 1198 pa_json_encoder *encoder = pa_json_encoder_new(); 1199 pa_json_encoder_begin_element_object(encoder); 1200 pa_json_encoder_add_member_int(encoder, "index", i->index); 1201 pa_json_encoder_add_member_string(encoder, "name", i->name); 1202 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 1203 pa_json_encoder_end_object(encoder); 1204 1205 char* json_str = pa_json_encoder_to_string_free(encoder); 1206 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1207 pa_xfree(json_str); 1208 } else { 1209 printf("%u\t%s\t%s\n", i->index, i->name, pa_strnull(i->driver)); 1210 } 1211 return; 1212 } 1213 1214 if (format == JSON) { 1215 pa_json_encoder *encoder = pa_json_encoder_new(); 1216 pa_json_encoder_begin_element_object(encoder); 1217 pa_json_encoder_add_member_int(encoder, "index", i->index); 1218 pa_json_encoder_add_member_string(encoder, "name", i->name); 1219 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 1220 i->owner_module != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "owner_module", t) : pa_json_encoder_add_member_null(encoder, "owner_module"); 1221 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 1222 pa_json_encoder_add_member_raw_json(encoder, "profiles", i->n_profiles > 0 ? pa_card_profile_info_2_to_json_object(i->profiles2) : "{}"); 1223 i->active_profile ? pa_json_encoder_add_member_string(encoder, "active_profile", i->active_profile->name) : pa_json_encoder_add_member_null(encoder, "active_profile"); 1224 pa_json_encoder_add_member_raw_json(encoder, "ports", pa_card_port_info_to_json_object(i->ports)); 1225 pa_json_encoder_end_object(encoder); 1226 1227 char* json_str = pa_json_encoder_to_string_free(encoder); 1228 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1229 pa_xfree(json_str); 1230 } else { 1231 printf(_("Card #%u\n" 1232 "\tName: %s\n" 1233 "\tDriver: %s\n" 1234 "\tOwner Module: %s\n" 1235 "\tProperties:\n\t\t%s\n"), 1236 i->index, 1237 i->name, 1238 pa_strnull(i->driver), 1239 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"), 1240 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 1241 1242 if (i->n_profiles > 0) { 1243 pa_card_profile_info2 **p; 1244 1245 printf(_("\tProfiles:\n")); 1246 for (p = i->profiles2; *p; p++) 1247 printf(_("\t\t%s: %s (sinks: %u, sources: %u, priority: %u, available: %s)\n"), (*p)->name, 1248 (*p)->description, (*p)->n_sinks, (*p)->n_sources, (*p)->priority, pa_yes_no_localised((*p)->available)); 1249 } 1250 1251 if (i->active_profile) 1252 printf(_("\tActive Profile: %s\n"), 1253 i->active_profile->name); 1254 1255 if (i->ports) { 1256 pa_card_port_info **p; 1257 1258 printf(_("\tPorts:\n")); 1259 for (p = i->ports; *p; p++) { 1260 pa_card_profile_info **pr = (*p)->profiles; 1261 printf(_("\t\t%s: %s (type: %s, priority: %u, latency offset: %" PRId64 " usec%s%s, %s)\n"), (*p)->name, 1262 (*p)->description, get_device_port_type((*p)->type), (*p)->priority, (*p)->latency_offset, 1263 (*p)->availability_group ? _(", availability group: ") : "", (*p)->availability_group ?: "", 1264 get_available_str((*p)->available)); 1265 1266 if (!pa_proplist_isempty((*p)->proplist)) { 1267 pa_xfree(pl); 1268 printf(_("\t\t\tProperties:\n\t\t\t\t%s\n"), pl = pa_proplist_to_string_sep((*p)->proplist, "\n\t\t\t\t")); 1269 } 1270 1271 if (pr) { 1272 printf(_("\t\t\tPart of profile(s): %s"), pa_strnull((*pr)->name)); 1273 pr++; 1274 while (*pr) { 1275 printf(", %s", pa_strnull((*pr)->name)); 1276 pr++; 1277 } 1278 printf("\n"); 1279 } 1280 } 1281 } 1282 } 1283 1284 pa_xfree(pl); 1285} 1286 1287static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { 1288 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]; 1289 char *pl; 1290 1291 if (format == JSON && json_encoder == NULL) { 1292 json_encoder = pa_json_encoder_new(); 1293 pa_json_encoder_begin_element_array(json_encoder); 1294 } 1295 1296 if (is_last < 0) { 1297 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c))); 1298 quit(1); 1299 return; 1300 } 1301 1302 if (is_last) { 1303 if (format == JSON) { 1304 pa_json_encoder_end_array_handler("sink_inputs"); 1305 } 1306 complete_action(); 1307 return; 1308 } 1309 1310 pa_assert(i); 1311 1312 if (nl && !short_list_format && format == TEXT) 1313 printf("\n"); 1314 nl = true; 1315 1316 pa_snprintf(t, sizeof(t), "%u", i->owner_module); 1317 pa_snprintf(k, sizeof(k), "%u", i->client); 1318 1319 char *sample_spec = pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); 1320 if (short_list_format) { 1321 if (format == JSON) { 1322 pa_json_encoder *encoder = pa_json_encoder_new(); 1323 pa_json_encoder_begin_element_object(encoder); 1324 pa_json_encoder_add_member_int(encoder, "index", i->index); 1325 pa_json_encoder_add_member_int(encoder, "sink", i->sink); 1326 i->client != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "client", k) : pa_json_encoder_add_member_null(encoder, "client"); 1327 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 1328 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 1329 pa_json_encoder_end_object(encoder); 1330 1331 char* json_str = pa_json_encoder_to_string_free(encoder); 1332 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1333 pa_xfree(json_str); 1334 } else { 1335 printf("%u\t%u\t%s\t%s\t%s\n", 1336 i->index, 1337 i->sink, 1338 i->client != PA_INVALID_INDEX ? k : "-", 1339 pa_strnull(i->driver), 1340 sample_spec); 1341 } 1342 return; 1343 } 1344 1345 char *channel_map = pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map); 1346 char *format_info = pa_format_info_snprint(f, sizeof(f), i->format); 1347 float balance = pa_cvolume_get_balance(&i->volume, &i->channel_map); 1348 if (format == JSON) { 1349 pa_json_encoder *encoder = pa_json_encoder_new(); 1350 pa_json_encoder_begin_element_object(encoder); 1351 pa_json_encoder_add_member_int(encoder, "index", i->index); 1352 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 1353 i->owner_module != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "owner_module", t) : pa_json_encoder_add_member_null(encoder, "owner_module"); 1354 i->client != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "client", k) : pa_json_encoder_add_member_null(encoder, "client"); 1355 pa_json_encoder_add_member_int(encoder, "sink", i->sink); 1356 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 1357 pa_json_encoder_add_member_string(encoder, "channel_map", channel_map); 1358 pa_json_encoder_add_member_string(encoder, "format", format_info); 1359 pa_json_encoder_add_member_bool(encoder, "corked", i->corked); 1360 pa_json_encoder_add_member_bool(encoder, "mute", i->mute); 1361 pa_json_encoder_add_member_raw_json(encoder, "volume", pa_cvolume_to_json_object(&i->volume, &i->channel_map, true)); 1362 pa_json_encoder_add_member_double(encoder, "balance", balance, 2); 1363 pa_json_encoder_add_member_double(encoder, "buffer_latency_usec", (double) i->buffer_usec, 2); 1364 pa_json_encoder_add_member_double(encoder, "sink_latency_usec", (double) i->sink_usec, 2); 1365 pa_json_encoder_add_member_string(encoder, "resample_method", i->resample_method); 1366 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 1367 pa_json_encoder_end_object(encoder); 1368 1369 char* json_str = pa_json_encoder_to_string_free(encoder); 1370 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1371 pa_xfree(json_str); 1372 } else { 1373 printf(_("Sink Input #%u\n" 1374 "\tDriver: %s\n" 1375 "\tOwner Module: %s\n" 1376 "\tClient: %s\n" 1377 "\tSink: %u\n" 1378 "\tSample Specification: %s\n" 1379 "\tChannel Map: %s\n" 1380 "\tFormat: %s\n" 1381 "\tCorked: %s\n" 1382 "\tMute: %s\n" 1383 "\tVolume: %s\n" 1384 "\t balance %0.2f\n" 1385 "\tBuffer Latency: %0.0f usec\n" 1386 "\tSink Latency: %0.0f usec\n" 1387 "\tResample method: %s\n" 1388 "\tProperties:\n\t\t%s\n"), 1389 i->index, 1390 pa_strnull(i->driver), 1391 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"), 1392 i->client != PA_INVALID_INDEX ? k : _("n/a"), 1393 i->sink, 1394 sample_spec, 1395 channel_map, 1396 format_info, 1397 pa_yes_no_localised(i->corked), 1398 pa_yes_no_localised(i->mute), 1399 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true), 1400 balance, 1401 (double) i->buffer_usec, 1402 (double) i->sink_usec, 1403 i->resample_method ? i->resample_method : _("n/a"), 1404 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 1405 } 1406 1407 pa_xfree(pl); 1408} 1409 1410static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) { 1411 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]; 1412 char *pl; 1413 1414 if (format == JSON && json_encoder == NULL) { 1415 json_encoder = pa_json_encoder_new(); 1416 pa_json_encoder_begin_element_array(json_encoder); 1417 } 1418 1419 if (is_last < 0) { 1420 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c))); 1421 quit(1); 1422 return; 1423 } 1424 1425 if (is_last) { 1426 if (format == JSON) { 1427 pa_json_encoder_end_array_handler("source_outputs"); 1428 } 1429 complete_action(); 1430 return; 1431 } 1432 1433 pa_assert(i); 1434 1435 if (nl && !short_list_format && format == TEXT) 1436 printf("\n"); 1437 nl = true; 1438 1439 pa_snprintf(t, sizeof(t), "%u", i->owner_module); 1440 pa_snprintf(k, sizeof(k), "%u", i->client); 1441 1442 char *sample_spec = pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); 1443 if (short_list_format) { 1444 if (format == JSON) { 1445 pa_json_encoder *encoder = pa_json_encoder_new(); 1446 pa_json_encoder_begin_element_object(encoder); 1447 pa_json_encoder_add_member_int(encoder, "index", i->index); 1448 pa_json_encoder_add_member_int(encoder, "source", i->source); 1449 i->client != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "client", k) : pa_json_encoder_add_member_null(encoder, "client"); 1450 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 1451 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 1452 pa_json_encoder_end_object(encoder); 1453 1454 char* json_str = pa_json_encoder_to_string_free(encoder); 1455 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1456 pa_xfree(json_str); 1457 } else { 1458 printf("%u\t%u\t%s\t%s\t%s\n", 1459 i->index, 1460 i->source, 1461 i->client != PA_INVALID_INDEX ? k : "-", 1462 pa_strnull(i->driver), 1463 sample_spec); 1464 } 1465 return; 1466 } 1467 1468 char *channel_map = pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map); 1469 char *format_info = pa_format_info_snprint(f, sizeof(f), i->format); 1470 float balance = pa_cvolume_get_balance(&i->volume, &i->channel_map); 1471 if (format == JSON) { 1472 pa_json_encoder *encoder = pa_json_encoder_new(); 1473 pa_json_encoder_begin_element_object(encoder); 1474 pa_json_encoder_add_member_int(encoder, "index", i->index); 1475 pa_json_encoder_add_member_string(encoder, "driver", i->driver); 1476 i->owner_module != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "owner_module", t) : pa_json_encoder_add_member_null(encoder, "owner_module"); 1477 i->client != PA_INVALID_INDEX ? pa_json_encoder_add_member_string(encoder, "client", k) : pa_json_encoder_add_member_null(encoder, "client"); 1478 pa_json_encoder_add_member_int(encoder, "source", i->source); 1479 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 1480 pa_json_encoder_add_member_string(encoder, "channel_map", channel_map); 1481 pa_json_encoder_add_member_string(encoder, "format", format_info); 1482 pa_json_encoder_add_member_bool(encoder, "corked", i->corked); 1483 pa_json_encoder_add_member_bool(encoder, "mute", i->mute); 1484 pa_json_encoder_add_member_raw_json(encoder, "volume", pa_cvolume_to_json_object(&i->volume, &i->channel_map, true)); 1485 pa_json_encoder_add_member_double(encoder, "balance", balance, 2); 1486 pa_json_encoder_add_member_double(encoder, "buffer_latency_usec", (double) i->buffer_usec, 2); 1487 pa_json_encoder_add_member_double(encoder, "source_latency_usec", (double) i->source_usec, 2); 1488 pa_json_encoder_add_member_string(encoder, "resample_method", i->resample_method); 1489 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 1490 pa_json_encoder_end_object(encoder); 1491 1492 char* json_str = pa_json_encoder_to_string_free(encoder); 1493 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1494 pa_xfree(json_str); 1495 } else { 1496 printf(_("Source Output #%u\n" 1497 "\tDriver: %s\n" 1498 "\tOwner Module: %s\n" 1499 "\tClient: %s\n" 1500 "\tSource: %u\n" 1501 "\tSample Specification: %s\n" 1502 "\tChannel Map: %s\n" 1503 "\tFormat: %s\n" 1504 "\tCorked: %s\n" 1505 "\tMute: %s\n" 1506 "\tVolume: %s\n" 1507 "\t balance %0.2f\n" 1508 "\tBuffer Latency: %0.0f usec\n" 1509 "\tSource Latency: %0.0f usec\n" 1510 "\tResample method: %s\n" 1511 "\tProperties:\n\t\t%s\n"), 1512 i->index, 1513 pa_strnull(i->driver), 1514 i->owner_module != PA_INVALID_INDEX ? t : _("n/a"), 1515 i->client != PA_INVALID_INDEX ? k : _("n/a"), 1516 i->source, 1517 sample_spec, 1518 channel_map, 1519 format_info, 1520 pa_yes_no_localised(i->corked), 1521 pa_yes_no_localised(i->mute), 1522 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true), 1523 balance, 1524 (double) i->buffer_usec, 1525 (double) i->source_usec, 1526 i->resample_method ? i->resample_method : _("n/a"), 1527 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 1528 } 1529 1530 pa_xfree(pl); 1531} 1532 1533static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) { 1534 char t[PA_BYTES_SNPRINT_MAX], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; 1535 char *pl; 1536 1537 if (format == JSON && json_encoder == NULL) { 1538 json_encoder = pa_json_encoder_new(); 1539 pa_json_encoder_begin_element_array(json_encoder); 1540 } 1541 1542 if (is_last < 0) { 1543 pa_log(_("Failed to get sample information: %s"), pa_strerror(pa_context_errno(c))); 1544 quit(1); 1545 return; 1546 } 1547 1548 if (is_last) { 1549 if (format == JSON) { 1550 pa_json_encoder_end_array_handler("samples"); 1551 } 1552 complete_action(); 1553 return; 1554 } 1555 1556 pa_assert(i); 1557 1558 if (nl && !short_list_format && format == TEXT) 1559 printf("\n"); 1560 nl = true; 1561 1562 pa_bytes_snprint(t, sizeof(t), i->bytes); 1563 1564 char *sample_spec = pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : short_list_format ? "-" : _("n/a"); 1565 double duration = (double) i->duration/1000000.0; 1566 if (short_list_format) { 1567 if (format == JSON) { 1568 pa_json_encoder *encoder = pa_json_encoder_new(); 1569 pa_json_encoder_begin_element_object(encoder); 1570 pa_json_encoder_add_member_int(encoder, "index", i->index); 1571 pa_json_encoder_add_member_string(encoder, "name", i->name); 1572 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 1573 pa_json_encoder_add_member_double(encoder, "duration", duration, 3); 1574 pa_json_encoder_end_object(encoder); 1575 1576 char* json_str = pa_json_encoder_to_string_free(encoder); 1577 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1578 pa_xfree(json_str); 1579 } else { 1580 printf("%u\t%s\t%s\t%0.3f\n", 1581 i->index, 1582 i->name, 1583 sample_spec, 1584 duration); 1585 } 1586 return; 1587 } 1588 1589 char *channel_map = pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : _("n/a"); 1590 float balance = pa_cvolume_get_balance(&i->volume, &i->channel_map); 1591 if (format == JSON) { 1592 pa_json_encoder *encoder = pa_json_encoder_new(); 1593 pa_json_encoder_begin_element_object(encoder); 1594 pa_json_encoder_add_member_int(encoder, "index", i->index); 1595 pa_json_encoder_add_member_string(encoder, "name", i->name); 1596 pa_json_encoder_add_member_string(encoder, "sample_specification", sample_spec); 1597 pa_json_encoder_add_member_string(encoder, "channel_map", channel_map); 1598 pa_json_encoder_add_member_raw_json(encoder, "volume", pa_cvolume_to_json_object(&i->volume, &i->channel_map, true)); 1599 pa_json_encoder_add_member_double(encoder, "balance", balance, 2); 1600 pa_json_encoder_add_member_double(encoder, "duration", duration, 3); 1601 pa_json_encoder_add_member_string(encoder, "size", t); 1602 pa_json_encoder_add_member_bool(encoder, "lazy", i->lazy); 1603 pa_json_encoder_add_member_string(encoder, "filename", i->filename); 1604 pa_json_encoder_add_member_raw_json(encoder, "properties", pl = pa_proplist_to_json_object(i->proplist)); 1605 pa_json_encoder_end_object(encoder); 1606 1607 char* json_str = pa_json_encoder_to_string_free(encoder); 1608 pa_json_encoder_add_element_raw_json(json_encoder, json_str); 1609 pa_xfree(json_str); 1610 } else { 1611 printf(_("Sample #%u\n" 1612 "\tName: %s\n" 1613 "\tSample Specification: %s\n" 1614 "\tChannel Map: %s\n" 1615 "\tVolume: %s\n" 1616 "\t balance %0.2f\n" 1617 "\tDuration: %0.1fs\n" 1618 "\tSize: %s\n" 1619 "\tLazy: %s\n" 1620 "\tFilename: %s\n" 1621 "\tProperties:\n\t\t%s\n"), 1622 i->index, 1623 i->name, 1624 sample_spec, 1625 channel_map, 1626 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true), 1627 balance, 1628 duration, 1629 t, 1630 pa_yes_no_localised(i->lazy), 1631 i->filename ? i->filename : _("n/a"), 1632 pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t")); 1633 } 1634 1635 pa_xfree(pl); 1636} 1637 1638static void simple_callback(pa_context *c, int success, void *userdata) { 1639 if (!success) { 1640 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c))); 1641 quit(1); 1642 return; 1643 } 1644 1645 complete_action(); 1646} 1647 1648static void index_callback(pa_context *c, uint32_t idx, void *userdata) { 1649 if (idx == PA_INVALID_INDEX) { 1650 pa_log(_("Failure: %s"), pa_strerror(pa_context_errno(c))); 1651 quit(1); 1652 return; 1653 } 1654 1655 if (format == JSON) { 1656 pa_json_encoder *encoder = pa_json_encoder_new(); 1657 pa_json_encoder_begin_element_object(encoder); 1658 pa_json_encoder_add_member_int(encoder, "index", idx); 1659 pa_json_encoder_end_object(encoder); 1660 1661 char* json_str = pa_json_encoder_to_string_free(encoder); 1662 printf("%s", json_str); 1663 pa_xfree(json_str); 1664 } else { 1665 printf("%u\n", idx); 1666 } 1667 1668 complete_action(); 1669} 1670 1671static void send_message_callback(pa_context *c, int success, char *response, void *userdata) { 1672 1673 if (!success) { 1674 pa_log(_("Send message failed: %s"), pa_strerror(pa_context_errno(c))); 1675 quit(1); 1676 return; 1677 } 1678 1679 if (format == JSON) { 1680 pa_json_encoder *encoder = pa_json_encoder_new(); 1681 pa_json_encoder_begin_element_object(encoder); 1682 pa_json_encoder_add_member_string(encoder, "response", response); 1683 pa_json_encoder_end_object(encoder); 1684 1685 char* json_str = pa_json_encoder_to_string_free(encoder); 1686 printf("%s", json_str); 1687 pa_xfree(json_str); 1688 } else { 1689 printf("%s\n", response); 1690 } 1691 1692 complete_action(); 1693} 1694 1695static void list_handlers_callback(pa_context *c, int success, char *response, void *userdata) { 1696 int err; 1697 pa_json_object *o; 1698 int i; 1699 const pa_json_object *v, *path, *description; 1700 1701 if (!success) { 1702 pa_log(_("list-handlers message failed: %s"), pa_strerror(pa_context_errno(c))); 1703 quit(1); 1704 return; 1705 } 1706 1707 // The response is already JSON encoded 1708 if (format == JSON) { 1709 printf("%s\n", response); 1710 fflush(stdout); 1711 complete_action(); 1712 return; 1713 } 1714 1715 o = pa_json_parse(response); 1716 1717 if (!o) { 1718 pa_log(_("list-handlers message response could not be parsed correctly")); 1719 pa_json_object_free(o); 1720 quit(1); 1721 return; 1722 } 1723 1724 if (pa_json_object_get_type(o) != PA_JSON_TYPE_ARRAY) { 1725 pa_log(_("list-handlers message response is not a JSON array")); 1726 pa_json_object_free(o); 1727 quit(1); 1728 return; 1729 } 1730 1731 err = 0; 1732 1733 for (i = 0; i < pa_json_object_get_array_length(o); ++i) { 1734 v = pa_json_object_get_array_member(o, i); 1735 if (pa_json_object_get_type(v) != PA_JSON_TYPE_OBJECT) { 1736 pa_log(_("list-handlers message response array element %d is not a JSON object"), i); 1737 err = -1; 1738 break; 1739 } 1740 1741 path = pa_json_object_get_object_member(v, "name"); 1742 if (!path || pa_json_object_get_type(path) != PA_JSON_TYPE_STRING) { 1743 err = -1; 1744 break; 1745 } 1746 description = pa_json_object_get_object_member(v, "description"); 1747 if (!description || pa_json_object_get_type(description) != PA_JSON_TYPE_STRING) { 1748 err = -1; 1749 break; 1750 } 1751 1752 if (short_list_format) { 1753 printf("%s\n", pa_json_object_get_string(path)); 1754 } else { 1755 if (nl) 1756 printf("\n"); 1757 nl = true; 1758 1759 printf("Message Handler %s\n" 1760 "\tDescription: %s\n", 1761 pa_json_object_get_string(path), 1762 pa_json_object_get_string(description)); 1763 } 1764 } 1765 1766 if (err < 0) { 1767 pa_log(_("list-handlers message response could not be parsed correctly")); 1768 pa_json_object_free(o); 1769 quit(1); 1770 return; 1771 } 1772 1773 pa_json_object_free(o); 1774 1775 complete_action(); 1776} 1777 1778static void volume_relative_adjust(pa_cvolume *cv) { 1779 pa_assert(volume_flags & VOL_RELATIVE); 1780 1781 /* Relative volume change is additive in case of UINT or PERCENT 1782 * and multiplicative for LINEAR or DECIBEL */ 1783 if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) { 1784 unsigned i; 1785 for (i = 0; i < cv->channels; i++) { 1786 if (cv->values[i] + volume.values[i] < PA_VOLUME_NORM) 1787 cv->values[i] = PA_VOLUME_MUTED; 1788 else 1789 cv->values[i] = cv->values[i] + volume.values[i] - PA_VOLUME_NORM; 1790 } 1791 } 1792 if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) 1793 pa_sw_cvolume_multiply(cv, cv, &volume); 1794} 1795 1796static void unload_module_by_name_callback(pa_context *c, const pa_module_info *i, int is_last, void *userdata) { 1797 static bool unloaded = false; 1798 1799 if (is_last < 0) { 1800 pa_log(_("Failed to get module information: %s"), pa_strerror(pa_context_errno(c))); 1801 quit(1); 1802 return; 1803 } 1804 1805 if (is_last) { 1806 if (unloaded == false) 1807 pa_log(_("Failed to unload module: Module %s not loaded"), module_name); 1808 complete_action(); 1809 return; 1810 } 1811 1812 pa_assert(i); 1813 1814 if (pa_streq(module_name, i->name)) { 1815 unloaded = true; 1816 actions++; 1817 pa_operation_unref(pa_context_unload_module(c, i->index, simple_callback, NULL)); 1818 } 1819} 1820 1821static void fill_volume(pa_cvolume *cv, unsigned supported) { 1822 if (volume.channels == 1) { 1823 pa_cvolume_set(&volume, supported, volume.values[0]); 1824 } else if (volume.channels != supported) { 1825 pa_log(ngettext("Failed to set volume: You tried to set volumes for %d channel, whereas channel(s) supported = %d\n", 1826 "Failed to set volume: You tried to set volumes for %d channels, whereas channel(s) supported = %d\n", 1827 volume.channels), 1828 volume.channels, supported); 1829 quit(1); 1830 return; 1831 } 1832 1833 if (volume_flags & VOL_RELATIVE) 1834 volume_relative_adjust(cv); 1835 else 1836 *cv = volume; 1837} 1838 1839static void get_sink_mute_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { 1840 if (is_last < 0) { 1841 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c))); 1842 quit(1); 1843 return; 1844 } 1845 1846 if (is_last) 1847 return; 1848 1849 pa_assert(i); 1850 1851 printf(("Mute: %s\n"), 1852 pa_yes_no_localised(i->mute)); 1853 1854 complete_action(); 1855} 1856 1857static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { 1858 if (is_last < 0) { 1859 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c))); 1860 quit(1); 1861 return; 1862 } 1863 1864 if (is_last) 1865 return; 1866 1867 pa_assert(i); 1868 1869 char cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; 1870 printf(("Volume: %s\n" 1871 " balance %0.2f\n"), 1872 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true), 1873 pa_cvolume_get_balance(&i->volume, &i->channel_map)); 1874 1875 complete_action(); 1876} 1877 1878static void set_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { 1879 pa_cvolume cv; 1880 1881 if (is_last < 0) { 1882 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c))); 1883 quit(1); 1884 return; 1885 } 1886 1887 if (is_last) 1888 return; 1889 1890 pa_assert(i); 1891 1892 cv = i->volume; 1893 fill_volume(&cv, i->channel_map.channels); 1894 1895 pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL)); 1896} 1897 1898static void get_source_mute_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { 1899 if (is_last < 0) { 1900 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c))); 1901 quit(1); 1902 return; 1903 } 1904 1905 if (is_last) 1906 return; 1907 1908 pa_assert(i); 1909 1910 printf(("Mute: %s\n"), 1911 pa_yes_no_localised(i->mute)); 1912 1913 complete_action(); 1914} 1915 1916static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { 1917 if (is_last < 0) { 1918 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c))); 1919 quit(1); 1920 return; 1921 } 1922 1923 if (is_last) 1924 return; 1925 1926 pa_assert(i); 1927 1928 char cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; 1929 printf(("Volume: %s\n" 1930 " balance %0.2f\n"), 1931 pa_cvolume_snprint_verbose(cv, sizeof(cv), &i->volume, &i->channel_map, true), 1932 pa_cvolume_get_balance(&i->volume, &i->channel_map)); 1933 1934 complete_action(); 1935} 1936 1937static void set_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { 1938 pa_cvolume cv; 1939 1940 if (is_last < 0) { 1941 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c))); 1942 quit(1); 1943 return; 1944 } 1945 1946 if (is_last) 1947 return; 1948 1949 pa_assert(i); 1950 1951 cv = i->volume; 1952 fill_volume(&cv, i->channel_map.channels); 1953 1954 pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL)); 1955} 1956 1957static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { 1958 pa_cvolume cv; 1959 1960 if (is_last < 0) { 1961 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c))); 1962 quit(1); 1963 return; 1964 } 1965 1966 if (is_last) 1967 return; 1968 1969 pa_assert(i); 1970 1971 cv = i->volume; 1972 fill_volume(&cv, i->channel_map.channels); 1973 1974 pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL)); 1975} 1976 1977static void get_source_output_volume_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) { 1978 pa_cvolume cv; 1979 1980 if (is_last < 0) { 1981 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c))); 1982 quit(1); 1983 return; 1984 } 1985 1986 if (is_last) 1987 return; 1988 1989 pa_assert(o); 1990 1991 cv = o->volume; 1992 fill_volume(&cv, o->channel_map.channels); 1993 1994 pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL)); 1995} 1996 1997static void sink_toggle_mute_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { 1998 if (is_last < 0) { 1999 pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c))); 2000 quit(1); 2001 return; 2002 } 2003 2004 if (is_last) 2005 return; 2006 2007 pa_assert(i); 2008 2009 pa_operation_unref(pa_context_set_sink_mute_by_name(c, i->name, !i->mute, simple_callback, NULL)); 2010} 2011 2012static void source_toggle_mute_callback(pa_context *c, const pa_source_info *o, int is_last, void *userdata) { 2013 if (is_last < 0) { 2014 pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c))); 2015 quit(1); 2016 return; 2017 } 2018 2019 if (is_last) 2020 return; 2021 2022 pa_assert(o); 2023 2024 pa_operation_unref(pa_context_set_source_mute_by_name(c, o->name, !o->mute, simple_callback, NULL)); 2025} 2026 2027static void sink_input_toggle_mute_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { 2028 if (is_last < 0) { 2029 pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c))); 2030 quit(1); 2031 return; 2032 } 2033 2034 if (is_last) 2035 return; 2036 2037 pa_assert(i); 2038 2039 pa_operation_unref(pa_context_set_sink_input_mute(c, i->index, !i->mute, simple_callback, NULL)); 2040} 2041 2042static void source_output_toggle_mute_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) { 2043 if (is_last < 0) { 2044 pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c))); 2045 quit(1); 2046 return; 2047 } 2048 2049 if (is_last) 2050 return; 2051 2052 pa_assert(o); 2053 2054 pa_operation_unref(pa_context_set_source_output_mute(c, o->index, !o->mute, simple_callback, NULL)); 2055} 2056 2057/* PA_MAX_FORMATS is defined in internal.h so we just define a sane value here */ 2058#define MAX_FORMATS 256 2059 2060static void set_sink_formats(pa_context *c, uint32_t sink, const char *str) { 2061 pa_format_info *f_arr[MAX_FORMATS] = { 0, }; 2062 char *format = NULL; 2063 const char *state = NULL; 2064 int i = 0; 2065 pa_operation *o = NULL; 2066 2067 while ((format = pa_split(str, ";", &state))) { 2068 pa_format_info *f = pa_format_info_from_string(pa_strip(format)); 2069 2070 if (!f) { 2071 pa_log(_("Failed to set format: invalid format string %s"), format); 2072 goto error; 2073 } 2074 2075 f_arr[i++] = f; 2076 pa_xfree(format); 2077 } 2078 2079 o = pa_ext_device_restore_save_formats(c, PA_DEVICE_TYPE_SINK, sink, i, f_arr, simple_callback, NULL); 2080 if (o) { 2081 pa_operation_unref(o); 2082 actions++; 2083 } 2084 2085done: 2086 if (format) 2087 pa_xfree(format); 2088 while (f_arr[i] && i--) 2089 pa_format_info_free(f_arr[i]); 2090 2091 return; 2092 2093error: 2094 while (f_arr[i] && i--) 2095 pa_format_info_free(f_arr[i]); 2096 quit(1); 2097 goto done; 2098} 2099 2100#ifdef SNDFILE_ENABLE 2101static void stream_state_callback(pa_stream *s, void *userdata) { 2102 pa_assert(s); 2103 2104 switch (pa_stream_get_state(s)) { 2105 case PA_STREAM_CREATING: 2106 case PA_STREAM_READY: 2107 break; 2108 2109 case PA_STREAM_TERMINATED: 2110 drain(); 2111 break; 2112 2113 case PA_STREAM_FAILED: 2114 default: 2115 pa_log(_("Failed to upload sample: %s"), pa_strerror(pa_context_errno(pa_stream_get_context(s)))); 2116 quit(1); 2117 } 2118} 2119 2120static void stream_write_callback(pa_stream *s, size_t length, void *userdata) { 2121 sf_count_t l; 2122 float *d; 2123 pa_assert(s && length && sndfile); 2124 2125 d = pa_xmalloc(length); 2126 2127 pa_assert(sample_length >= length); 2128 l = (sf_count_t) (length/pa_frame_size(&sample_spec)); 2129 2130 if ((sf_readf_float(sndfile, d, l)) != l) { 2131 pa_xfree(d); 2132 pa_log(_("Premature end of file")); 2133 quit(1); 2134 return; 2135 } 2136 2137 pa_stream_write(s, d, length, pa_xfree, 0, PA_SEEK_RELATIVE); 2138 2139 sample_length -= length; 2140 2141 if (sample_length <= 0) { 2142 pa_stream_set_write_callback(sample_stream, NULL, NULL); 2143 pa_stream_finish_upload(sample_stream); 2144 } 2145} 2146#endif 2147 2148static const char *subscription_event_type_to_string(pa_subscription_event_type_t t) { 2149 2150 switch (t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { 2151 2152 case PA_SUBSCRIPTION_EVENT_NEW: 2153 return _("new"); 2154 2155 case PA_SUBSCRIPTION_EVENT_CHANGE: 2156 return _("change"); 2157 2158 case PA_SUBSCRIPTION_EVENT_REMOVE: 2159 return _("remove"); 2160 } 2161 2162 return _("unknown"); 2163} 2164 2165static const char *subscription_event_facility_to_string(pa_subscription_event_type_t t) { 2166 2167 switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { 2168 2169 case PA_SUBSCRIPTION_EVENT_SINK: 2170 return _("sink"); 2171 2172 case PA_SUBSCRIPTION_EVENT_SOURCE: 2173 return _("source"); 2174 2175 case PA_SUBSCRIPTION_EVENT_SINK_INPUT: 2176 return _("sink-input"); 2177 2178 case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: 2179 return _("source-output"); 2180 2181 case PA_SUBSCRIPTION_EVENT_MODULE: 2182 return _("module"); 2183 2184 case PA_SUBSCRIPTION_EVENT_CLIENT: 2185 return _("client"); 2186 2187 case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE: 2188 return _("sample-cache"); 2189 2190 case PA_SUBSCRIPTION_EVENT_SERVER: 2191 return _("server"); 2192 2193 case PA_SUBSCRIPTION_EVENT_CARD: 2194 return _("card"); 2195 } 2196 2197 return _("unknown"); 2198} 2199 2200static void context_subscribe_callback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { 2201 pa_assert(c); 2202 2203 if (format == JSON) { 2204 pa_json_encoder *encoder = pa_json_encoder_new(); 2205 pa_json_encoder_begin_element_object(encoder); 2206 pa_json_encoder_add_member_int(encoder, "index", idx); 2207 pa_json_encoder_add_member_string(encoder, "event", subscription_event_type_to_string(t)); 2208 pa_json_encoder_add_member_string(encoder, "on", subscription_event_facility_to_string(t)); 2209 pa_json_encoder_end_object(encoder); 2210 2211 char* json_str = pa_json_encoder_to_string_free(encoder); 2212 printf("%s", json_str); 2213 pa_xfree(json_str); 2214 } else { 2215 printf(_("Event '%s' on %s #%u\n"), 2216 subscription_event_type_to_string(t), 2217 subscription_event_facility_to_string(t), 2218 idx); 2219 } 2220 fflush(stdout); 2221} 2222 2223static void context_state_callback(pa_context *c, void *userdata) { 2224 pa_operation *o = NULL; 2225 2226 pa_assert(c); 2227 2228 switch (pa_context_get_state(c)) { 2229 case PA_CONTEXT_CONNECTING: 2230 case PA_CONTEXT_AUTHORIZING: 2231 case PA_CONTEXT_SETTING_NAME: 2232 break; 2233 2234 case PA_CONTEXT_READY: 2235 switch (action) { 2236 case STAT: 2237 o = pa_context_stat(c, stat_callback, NULL); 2238 break; 2239 2240 case INFO: 2241 o = pa_context_get_server_info(c, get_server_info_callback, NULL); 2242 break; 2243 2244 case PLAY_SAMPLE: 2245 o = pa_context_play_sample(c, sample_name, sink_name, PA_VOLUME_NORM, simple_callback, NULL); 2246 break; 2247 2248 case REMOVE_SAMPLE: 2249 o = pa_context_remove_sample(c, sample_name, simple_callback, NULL); 2250 break; 2251#ifdef SNDFILE_ENABLE 2252 case UPLOAD_SAMPLE: 2253 sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL); 2254 pa_assert(sample_stream); 2255 2256 pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); 2257 pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); 2258 pa_stream_connect_upload(sample_stream, sample_length); 2259 actions++; 2260 break; 2261#endif 2262 case EXIT: 2263 o = pa_context_exit_daemon(c, simple_callback, NULL); 2264 break; 2265 2266 case LIST: 2267 if (list_type) { 2268 if (pa_streq(list_type, "modules")) 2269 o = pa_context_get_module_info_list(c, get_module_info_callback, NULL); 2270 else if (pa_streq(list_type, "sinks")) 2271 o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL); 2272 else if (pa_streq(list_type, "sources")) 2273 o = pa_context_get_source_info_list(c, get_source_info_callback, NULL); 2274 else if (pa_streq(list_type, "sink-inputs")) 2275 o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL); 2276 else if (pa_streq(list_type, "source-outputs")) 2277 o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL); 2278 else if (pa_streq(list_type, "clients")) 2279 o = pa_context_get_client_info_list(c, get_client_info_callback, NULL); 2280 else if (pa_streq(list_type, "samples")) 2281 o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL); 2282 else if (pa_streq(list_type, "cards")) 2283 o = pa_context_get_card_info_list(c, get_card_info_callback, NULL); 2284 else if (pa_streq(list_type, "message-handlers")) 2285 o = pa_context_send_message_to_object(c, "/core", "list-handlers", NULL, list_handlers_callback, NULL); 2286 else 2287 pa_assert_not_reached(); 2288 } else { 2289 if (format == JSON) { 2290 list_encoder = pa_json_encoder_new(); 2291 pa_json_encoder_begin_element_object(list_encoder); 2292 } 2293 2294 o = pa_context_get_module_info_list(c, get_module_info_callback, NULL); 2295 if (o) { 2296 pa_operation_unref(o); 2297 actions++; 2298 } 2299 2300 o = pa_context_get_sink_info_list(c, get_sink_info_callback, NULL); 2301 if (o) { 2302 pa_operation_unref(o); 2303 actions++; 2304 } 2305 2306 o = pa_context_get_source_info_list(c, get_source_info_callback, NULL); 2307 if (o) { 2308 pa_operation_unref(o); 2309 actions++; 2310 } 2311 o = pa_context_get_sink_input_info_list(c, get_sink_input_info_callback, NULL); 2312 if (o) { 2313 pa_operation_unref(o); 2314 actions++; 2315 } 2316 2317 o = pa_context_get_source_output_info_list(c, get_source_output_info_callback, NULL); 2318 if (o) { 2319 pa_operation_unref(o); 2320 actions++; 2321 } 2322 2323 o = pa_context_get_client_info_list(c, get_client_info_callback, NULL); 2324 if (o) { 2325 pa_operation_unref(o); 2326 actions++; 2327 } 2328 2329 o = pa_context_get_sample_info_list(c, get_sample_info_callback, NULL); 2330 if (o) { 2331 pa_operation_unref(o); 2332 actions++; 2333 } 2334 2335 o = pa_context_get_card_info_list(c, get_card_info_callback, NULL); 2336 if (o) { 2337 pa_operation_unref(o); 2338 actions++; 2339 } 2340 2341 o = NULL; 2342 } 2343 break; 2344 2345 case MOVE_SINK_INPUT: 2346 o = pa_context_move_sink_input_by_name(c, sink_input_idx, sink_name, simple_callback, NULL); 2347 break; 2348 2349 case MOVE_SOURCE_OUTPUT: 2350 o = pa_context_move_source_output_by_name(c, source_output_idx, source_name, simple_callback, NULL); 2351 break; 2352 2353 case LOAD_MODULE: 2354 o = pa_context_load_module(c, module_name, module_args, index_callback, NULL); 2355 break; 2356 2357 case UNLOAD_MODULE: 2358 if (module_name) 2359 o = pa_context_get_module_info_list(c, unload_module_by_name_callback, NULL); 2360 else 2361 o = pa_context_unload_module(c, module_index, simple_callback, NULL); 2362 break; 2363 2364 case SUSPEND_SINK: 2365 if (sink_name) 2366 o = pa_context_suspend_sink_by_name(c, sink_name, suspend, simple_callback, NULL); 2367 else 2368 o = pa_context_suspend_sink_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL); 2369 break; 2370 2371 case SUSPEND_SOURCE: 2372 if (source_name) 2373 o = pa_context_suspend_source_by_name(c, source_name, suspend, simple_callback, NULL); 2374 else 2375 o = pa_context_suspend_source_by_index(c, PA_INVALID_INDEX, suspend, simple_callback, NULL); 2376 break; 2377 2378 case SET_CARD_PROFILE: 2379 o = pa_context_set_card_profile_by_name(c, card_name, profile_name, simple_callback, NULL); 2380 break; 2381 2382 case SET_SINK_PORT: 2383 o = pa_context_set_sink_port_by_name(c, sink_name, port_name, simple_callback, NULL); 2384 break; 2385 2386 case GET_DEFAULT_SINK: 2387 o = pa_context_get_server_info(c, get_default_sink, NULL); 2388 break; 2389 2390 case SET_DEFAULT_SINK: 2391 o = pa_context_set_default_sink(c, sink_name, simple_callback, NULL); 2392 break; 2393 2394 case SET_SOURCE_PORT: 2395 o = pa_context_set_source_port_by_name(c, source_name, port_name, simple_callback, NULL); 2396 break; 2397 2398 case GET_DEFAULT_SOURCE: 2399 o = pa_context_get_server_info(c, get_default_source, NULL); 2400 break; 2401 2402 case SET_DEFAULT_SOURCE: 2403 o = pa_context_set_default_source(c, source_name, simple_callback, NULL); 2404 break; 2405 2406 case GET_SINK_MUTE: 2407 o = pa_context_get_sink_info_by_name(c, sink_name, get_sink_mute_callback, NULL); 2408 break; 2409 2410 case SET_SINK_MUTE: 2411 if (mute == TOGGLE_MUTE) 2412 o = pa_context_get_sink_info_by_name(c, sink_name, sink_toggle_mute_callback, NULL); 2413 else 2414 o = pa_context_set_sink_mute_by_name(c, sink_name, mute, simple_callback, NULL); 2415 break; 2416 2417 case GET_SOURCE_MUTE: 2418 o = pa_context_get_source_info_by_name(c, source_name, get_source_mute_callback, NULL); 2419 break; 2420 2421 case SET_SOURCE_MUTE: 2422 if (mute == TOGGLE_MUTE) 2423 o = pa_context_get_source_info_by_name(c, source_name, source_toggle_mute_callback, NULL); 2424 else 2425 o = pa_context_set_source_mute_by_name(c, source_name, mute, simple_callback, NULL); 2426 break; 2427 2428 case SET_SINK_INPUT_MUTE: 2429 if (mute == TOGGLE_MUTE) 2430 o = pa_context_get_sink_input_info(c, sink_input_idx, sink_input_toggle_mute_callback, NULL); 2431 else 2432 o = pa_context_set_sink_input_mute(c, sink_input_idx, mute, simple_callback, NULL); 2433 break; 2434 2435 case SET_SOURCE_OUTPUT_MUTE: 2436 if (mute == TOGGLE_MUTE) 2437 o = pa_context_get_source_output_info(c, source_output_idx, source_output_toggle_mute_callback, NULL); 2438 else 2439 o = pa_context_set_source_output_mute(c, source_output_idx, mute, simple_callback, NULL); 2440 break; 2441 2442 case GET_SINK_VOLUME: 2443 o = pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL); 2444 break; 2445 2446 case SET_SINK_VOLUME: 2447 o = pa_context_get_sink_info_by_name(c, sink_name, set_sink_volume_callback, NULL); 2448 break; 2449 2450 case GET_SOURCE_VOLUME: 2451 o = pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL); 2452 break; 2453 2454 case SET_SOURCE_VOLUME: 2455 o = pa_context_get_source_info_by_name(c, source_name, set_source_volume_callback, NULL); 2456 break; 2457 2458 case SET_SINK_INPUT_VOLUME: 2459 o = pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL); 2460 break; 2461 2462 case SET_SOURCE_OUTPUT_VOLUME: 2463 o = pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL); 2464 break; 2465 2466 case SET_SINK_FORMATS: 2467 set_sink_formats(c, sink_idx, formats); 2468 break; 2469 2470 case SET_PORT_LATENCY_OFFSET: 2471 o = pa_context_set_port_latency_offset(c, card_name, port_name, latency_offset, simple_callback, NULL); 2472 break; 2473 2474 case SEND_MESSAGE: 2475 o = pa_context_send_message_to_object(c, object_path, message, message_args, send_message_callback, NULL); 2476 break; 2477 2478 case SUBSCRIBE: 2479 pa_context_set_subscribe_callback(c, context_subscribe_callback, NULL); 2480 2481 o = pa_context_subscribe(c, 2482 PA_SUBSCRIPTION_MASK_SINK| 2483 PA_SUBSCRIPTION_MASK_SOURCE| 2484 PA_SUBSCRIPTION_MASK_SINK_INPUT| 2485 PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| 2486 PA_SUBSCRIPTION_MASK_MODULE| 2487 PA_SUBSCRIPTION_MASK_CLIENT| 2488 PA_SUBSCRIPTION_MASK_SAMPLE_CACHE| 2489 PA_SUBSCRIPTION_MASK_SERVER| 2490 PA_SUBSCRIPTION_MASK_CARD, 2491 NULL, 2492 NULL); 2493 break; 2494 2495 default: 2496 pa_assert_not_reached(); 2497 } 2498 2499 if (o) { 2500 pa_operation_unref(o); 2501 actions++; 2502 } 2503 2504 if (actions == 0) { 2505 pa_log("Operation failed: %s", pa_strerror(pa_context_errno(c))); 2506 quit(1); 2507 } 2508 2509 break; 2510 2511 case PA_CONTEXT_TERMINATED: 2512 quit(0); 2513 break; 2514 2515 case PA_CONTEXT_FAILED: 2516 default: 2517 pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c))); 2518 quit(1); 2519 } 2520} 2521 2522static void exit_signal_callback(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata) { 2523 pa_log(_("Got SIGINT, exiting.")); 2524 quit(0); 2525} 2526 2527static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flags *vol_flags) { 2528 double v; 2529 char *vs; 2530 const char *atod_input; 2531 2532 pa_assert(vol_spec); 2533 pa_assert(vol); 2534 pa_assert(vol_flags); 2535 2536 vs = pa_xstrdup(vol_spec); 2537 2538 *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE; 2539 if (pa_endswith(vs, "%")) { 2540 *vol_flags |= VOL_PERCENT; 2541 vs[strlen(vs)-1] = 0; 2542 } 2543 else if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) { 2544 *vol_flags |= VOL_DECIBEL; 2545 vs[strlen(vs)-2] = 0; 2546 } 2547 else if (strchr(vs, '.')) 2548 *vol_flags |= VOL_LINEAR; 2549 2550 atod_input = vs; 2551 2552 if (atod_input[0] == '+') 2553 atod_input++; /* pa_atod() doesn't accept leading '+', so skip it. */ 2554 2555 if (pa_atod(atod_input, &v) < 0) { 2556 pa_log(_("Invalid volume specification")); 2557 pa_xfree(vs); 2558 return -1; 2559 } 2560 2561 pa_xfree(vs); 2562 2563 if (*vol_flags & VOL_RELATIVE) { 2564 switch (*vol_flags & 0x0F) { 2565 case VOL_UINT: 2566 v += (double) PA_VOLUME_NORM; 2567 break; 2568 case VOL_PERCENT: 2569 v += 100.0; 2570 break; 2571 case VOL_LINEAR: 2572 v += 1.0; 2573 break; 2574 } 2575 } 2576 2577 switch (*vol_flags & 0x0F) { 2578 case VOL_PERCENT: 2579 v = v * (double) PA_VOLUME_NORM / 100; 2580 break; 2581 case VOL_LINEAR: 2582 v = pa_sw_volume_from_linear(v); 2583 break; 2584 case VOL_DECIBEL: 2585 v = pa_sw_volume_from_dB(v); 2586 break; 2587 } 2588 2589 if (!PA_VOLUME_IS_VALID((pa_volume_t) v)) { 2590 pa_log(_("Volume outside permissible range.\n")); 2591 return -1; 2592 } 2593 2594 *vol = (pa_volume_t) v; 2595 2596 return 0; 2597} 2598 2599static int parse_volumes(char *args[], unsigned n) { 2600 unsigned i; 2601 2602 if (n >= PA_CHANNELS_MAX) { 2603 pa_log(_("Invalid number of volume specifications.\n")); 2604 return -1; 2605 } 2606 2607 volume.channels = n; 2608 for (i = 0; i < volume.channels; i++) { 2609 enum volume_flags flags = 0; 2610 2611 if (parse_volume(args[i], &volume.values[i], &flags) < 0) 2612 return -1; 2613 2614 if (i > 0 && flags != volume_flags) { 2615 pa_log(_("Inconsistent volume specification.\n")); 2616 return -1; 2617 } else 2618 volume_flags = flags; 2619 } 2620 2621 return 0; 2622} 2623 2624static enum mute_flags parse_mute(const char *mute_text) { 2625 int b; 2626 2627 pa_assert(mute_text); 2628 2629 if (pa_streq("toggle", mute_text)) 2630 return TOGGLE_MUTE; 2631 2632 b = pa_parse_boolean(mute_text); 2633 switch (b) { 2634 case 0: 2635 return UNMUTE; 2636 case 1: 2637 return MUTE; 2638 default: 2639 return INVALID_MUTE; 2640 } 2641} 2642 2643static void help(const char *argv0) { 2644 2645 printf("%s %s %s\n", argv0, _("[options]"), "stat"); 2646 printf("%s %s %s\n", argv0, _("[options]"), "info"); 2647 printf("%s %s %s %s\n", argv0, _("[options]"), "list [short]", _("[TYPE]")); 2648 printf("%s %s %s\n", argv0, _("[options]"), "exit"); 2649 printf("%s %s %s %s\n", argv0, _("[options]"), "upload-sample", _("FILENAME [NAME]")); 2650 printf("%s %s %s %s\n", argv0, _("[options]"), "play-sample ", _("NAME [SINK]")); 2651 printf("%s %s %s %s\n", argv0, _("[options]"), "remove-sample ", _("NAME")); 2652 printf("%s %s %s %s\n", argv0, _("[options]"), "load-module ", _("NAME [ARGS ...]")); 2653 printf("%s %s %s %s\n", argv0, _("[options]"), "unload-module ", _("NAME|#N")); 2654 printf("%s %s %s %s\n", argv0, _("[options]"), "move-(sink-input|source-output)", _("#N SINK|SOURCE")); 2655 printf("%s %s %s %s\n", argv0, _("[options]"), "suspend-(sink|source)", _("NAME|#N 1|0")); 2656 printf("%s %s %s %s\n", argv0, _("[options]"), "set-card-profile ", _("CARD PROFILE")); 2657 printf("%s %s %s\n", argv0, _("[options]"), "get-default-(sink|source)"); 2658 printf("%s %s %s %s\n", argv0, _("[options]"), "set-default-(sink|source)", _("NAME")); 2659 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-port", _("NAME|#N PORT")); 2660 printf("%s %s %s %s\n", argv0, _("[options]"), "get-(sink|source)-volume", _("NAME|#N")); 2661 printf("%s %s %s %s\n", argv0, _("[options]"), "get-(sink|source)-mute", _("NAME|#N")); 2662 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-volume", _("NAME|#N VOLUME [VOLUME ...]")); 2663 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-volume", _("#N VOLUME [VOLUME ...]")); 2664 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink|source)-mute", _("NAME|#N 1|0|toggle")); 2665 printf("%s %s %s %s\n", argv0, _("[options]"), "set-(sink-input|source-output)-mute", _("#N 1|0|toggle")); 2666 printf("%s %s %s %s\n", argv0, _("[options]"), "set-sink-formats", _("#N FORMATS")); 2667 printf("%s %s %s %s\n", argv0, _("[options]"), "set-port-latency-offset", _("CARD-NAME|CARD-#N PORT OFFSET")); 2668 printf("%s %s %s %s\n", argv0, _("[options]"), "send-message", _("RECIPIENT MESSAGE [MESSAGE_PARAMETERS]")); 2669 printf("%s %s %s\n", argv0, _("[options]"), "subscribe"); 2670 printf(_("\nThe special names @DEFAULT_SINK@, @DEFAULT_SOURCE@ and @DEFAULT_MONITOR@\n" 2671 "can be used to specify the default sink, source and monitor.\n")); 2672 2673 printf(_("\n" 2674 " -h, --help Show this help\n" 2675 " --version Show version\n\n" 2676 " -f, --format=FORMAT The format of the output. Either \"normal\" or \"json\"\n" 2677 " -s, --server=SERVER The name of the server to connect to\n" 2678 " -n, --client-name=NAME How to call this client on the server\n")); 2679} 2680 2681enum { 2682 ARG_VERSION = 256 2683}; 2684 2685int main(int argc, char *argv[]) { 2686 pa_mainloop *m = NULL; 2687 int ret = 1, c; 2688 char *server = NULL, *opt_format = NULL, *bn; 2689 2690 static const struct option long_options[] = { 2691 {"server", 1, NULL, 's'}, 2692 {"client-name", 1, NULL, 'n'}, 2693 {"format", 1, NULL, 'f'}, 2694 {"version", 0, NULL, ARG_VERSION}, 2695 {"help", 0, NULL, 'h'}, 2696 {NULL, 0, NULL, 0} 2697 }; 2698 2699 setlocale(LC_ALL, ""); 2700#ifdef ENABLE_NLS 2701 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); 2702#endif 2703 2704 bn = pa_path_get_filename(argv[0]); 2705 2706 proplist = pa_proplist_new(); 2707 2708 while ((c = getopt_long(argc, argv, "+s:n:f:h", long_options, NULL)) != -1) { 2709 switch (c) { 2710 case 'h' : 2711 help(bn); 2712 ret = 0; 2713 goto quit; 2714 2715 case ARG_VERSION: 2716 printf(_("pactl %s\n" 2717 "Compiled with libpulse %s\n" 2718 "Linked with libpulse %s\n"), 2719 PACKAGE_VERSION, 2720 pa_get_headers_version(), 2721 pa_get_library_version()); 2722 ret = 0; 2723 goto quit; 2724 2725 case 's': 2726 pa_xfree(server); 2727 server = pa_xstrdup(optarg); 2728 break; 2729 2730 case 'f': 2731 opt_format = pa_xstrdup(optarg); 2732 break; 2733 2734 case 'n': { 2735 char *t; 2736 2737 if (!(t = pa_locale_to_utf8(optarg)) || 2738 pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) { 2739 2740 pa_log(_("Invalid client name '%s'"), t ? t : optarg); 2741 pa_xfree(t); 2742 goto quit; 2743 } 2744 2745 pa_xfree(t); 2746 break; 2747 } 2748 2749 default: 2750 goto quit; 2751 } 2752 } 2753 2754 if (!opt_format || pa_streq(opt_format, "text")) { 2755 format = TEXT; 2756 } else if (pa_streq(opt_format, "json")) { 2757 format = JSON; 2758 setlocale(LC_NUMERIC, "C"); 2759 } else { 2760 pa_log(_("Invalid format value '%s'"), opt_format); 2761 goto quit; 2762 } 2763 2764 if (optind < argc) { 2765 if (pa_streq(argv[optind], "stat")) { 2766 action = STAT; 2767 2768 } else if (pa_streq(argv[optind], "info")) 2769 action = INFO; 2770 2771 else if (pa_streq(argv[optind], "exit")) 2772 action = EXIT; 2773 2774 else if (pa_streq(argv[optind], "list")) { 2775 action = LIST; 2776 2777 for (int i = optind+1; i < argc; i++) { 2778 if (pa_streq(argv[i], "modules") || pa_streq(argv[i], "clients") || 2779 pa_streq(argv[i], "sinks") || pa_streq(argv[i], "sink-inputs") || 2780 pa_streq(argv[i], "sources") || pa_streq(argv[i], "source-outputs") || 2781 pa_streq(argv[i], "samples") || pa_streq(argv[i], "cards") || 2782 pa_streq(argv[i], "message-handlers")) { 2783 list_type = pa_xstrdup(argv[i]); 2784 } else if (pa_streq(argv[i], "short")) { 2785 short_list_format = true; 2786 } else { 2787 pa_log(_("Specify nothing, or one of: %s"), "modules, sinks, sources, sink-inputs, source-outputs, clients, samples, cards, message-handlers"); 2788 goto quit; 2789 } 2790 } 2791 2792 } else if (pa_streq(argv[optind], "upload-sample")) { 2793#ifdef SNDFILE_ENABLE 2794 struct SF_INFO sfi; 2795 action = UPLOAD_SAMPLE; 2796 2797 if (optind+1 >= argc) { 2798 pa_log(_("Please specify a sample file to load")); 2799 goto quit; 2800 } 2801 2802 if (optind+2 < argc) 2803 sample_name = pa_xstrdup(argv[optind+2]); 2804 else { 2805 char *f = pa_path_get_filename(argv[optind+1]); 2806 sample_name = pa_xstrndup(f, strcspn(f, ".")); 2807 } 2808 2809 pa_zero(sfi); 2810 if (!(sndfile = sf_open(argv[optind+1], SFM_READ, &sfi))) { 2811 pa_log(_("Failed to open sound file.")); 2812 goto quit; 2813 } 2814 2815 if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) { 2816 pa_log(_("Failed to determine sample specification from file.")); 2817 goto quit; 2818 } 2819 sample_spec.format = PA_SAMPLE_FLOAT32; 2820 2821 if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) { 2822 if (sample_spec.channels > 2) 2823 pa_log(_("Warning: Failed to determine sample specification from file.")); 2824 pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); 2825 } 2826 2827 pa_assert(pa_channel_map_compatible(&channel_map, &sample_spec)); 2828 sample_length = (size_t) sfi.frames*pa_frame_size(&sample_spec); 2829#endif 2830 } else if (pa_streq(argv[optind], "play-sample")) { 2831 action = PLAY_SAMPLE; 2832 if (argc != optind+2 && argc != optind+3) { 2833 pa_log(_("You have to specify a sample name to play")); 2834 goto quit; 2835 } 2836 2837 sample_name = pa_xstrdup(argv[optind+1]); 2838 2839 if (optind+2 < argc) 2840 sink_name = pa_xstrdup(argv[optind+2]); 2841 2842 } else if (pa_streq(argv[optind], "remove-sample")) { 2843 action = REMOVE_SAMPLE; 2844 if (argc != optind+2) { 2845 pa_log(_("You have to specify a sample name to remove")); 2846 goto quit; 2847 } 2848 2849 sample_name = pa_xstrdup(argv[optind+1]); 2850 2851 } else if (pa_streq(argv[optind], "move-sink-input")) { 2852 action = MOVE_SINK_INPUT; 2853 if (argc != optind+3) { 2854 pa_log(_("You have to specify a sink input index and a sink")); 2855 goto quit; 2856 } 2857 2858 sink_input_idx = (uint32_t) atoi(argv[optind+1]); 2859 sink_name = pa_xstrdup(argv[optind+2]); 2860 2861 } else if (pa_streq(argv[optind], "move-source-output")) { 2862 action = MOVE_SOURCE_OUTPUT; 2863 if (argc != optind+3) { 2864 pa_log(_("You have to specify a source output index and a source")); 2865 goto quit; 2866 } 2867 2868 source_output_idx = (uint32_t) atoi(argv[optind+1]); 2869 source_name = pa_xstrdup(argv[optind+2]); 2870 2871 } else if (pa_streq(argv[optind], "load-module")) { 2872 int i; 2873 size_t n = 0; 2874 char *p; 2875 2876 action = LOAD_MODULE; 2877 2878 if (argc <= optind+1) { 2879 pa_log(_("You have to specify a module name and arguments.")); 2880 goto quit; 2881 } 2882 2883 module_name = argv[optind+1]; 2884 2885 for (i = optind+2; i < argc; i++) 2886 n += strlen(argv[i])+1; 2887 2888 if (n > 0) { 2889 p = module_args = pa_xmalloc(n); 2890 2891 for (i = optind+2; i < argc; i++) 2892 p += sprintf(p, "%s%s", p == module_args ? "" : " ", argv[i]); 2893 } 2894 2895 } else if (pa_streq(argv[optind], "unload-module")) { 2896 action = UNLOAD_MODULE; 2897 2898 if (argc != optind+2) { 2899 pa_log(_("You have to specify a module index or name")); 2900 goto quit; 2901 } 2902 2903 if (pa_atou(argv[optind + 1], &module_index) < 0) 2904 module_name = argv[optind + 1]; 2905 2906 } else if (pa_streq(argv[optind], "suspend-sink")) { 2907 int b; 2908 2909 action = SUSPEND_SINK; 2910 2911 if (argc > optind+3 || optind+1 >= argc) { 2912 pa_log(_("You may not specify more than one sink. You have to specify a boolean value.")); 2913 goto quit; 2914 } 2915 2916 if ((b = pa_parse_boolean(argv[argc-1])) < 0) { 2917 pa_log(_("Invalid suspend specification.")); 2918 goto quit; 2919 } 2920 2921 suspend = !!b; 2922 2923 if (argc > optind+2) 2924 sink_name = pa_xstrdup(argv[optind+1]); 2925 2926 } else if (pa_streq(argv[optind], "suspend-source")) { 2927 int b; 2928 2929 action = SUSPEND_SOURCE; 2930 2931 if (argc > optind+3 || optind+1 >= argc) { 2932 pa_log(_("You may not specify more than one source. You have to specify a boolean value.")); 2933 goto quit; 2934 } 2935 2936 if ((b = pa_parse_boolean(argv[argc-1])) < 0) { 2937 pa_log(_("Invalid suspend specification.")); 2938 goto quit; 2939 } 2940 2941 suspend = !!b; 2942 2943 if (argc > optind+2) 2944 source_name = pa_xstrdup(argv[optind+1]); 2945 } else if (pa_streq(argv[optind], "set-card-profile")) { 2946 action = SET_CARD_PROFILE; 2947 2948 if (argc != optind+3) { 2949 pa_log(_("You have to specify a card name/index and a profile name")); 2950 goto quit; 2951 } 2952 2953 card_name = pa_xstrdup(argv[optind+1]); 2954 profile_name = pa_xstrdup(argv[optind+2]); 2955 2956 } else if (pa_streq(argv[optind], "set-sink-port")) { 2957 action = SET_SINK_PORT; 2958 2959 if (argc != optind+3) { 2960 pa_log(_("You have to specify a sink name/index and a port name")); 2961 goto quit; 2962 } 2963 2964 sink_name = pa_xstrdup(argv[optind+1]); 2965 port_name = pa_xstrdup(argv[optind+2]); 2966 2967 } else if (pa_streq(argv[optind], "set-default-sink")) { 2968 action = SET_DEFAULT_SINK; 2969 2970 if (argc != optind+2) { 2971 pa_log(_("You have to specify a sink name")); 2972 goto quit; 2973 } 2974 2975 sink_name = pa_xstrdup(argv[optind+1]); 2976 2977 } else if (pa_streq(argv[optind], "get-default-sink")) { 2978 action = GET_DEFAULT_SINK; 2979 2980 } else if (pa_streq(argv[optind], "set-source-port")) { 2981 action = SET_SOURCE_PORT; 2982 2983 if (argc != optind+3) { 2984 pa_log(_("You have to specify a source name/index and a port name")); 2985 goto quit; 2986 } 2987 2988 source_name = pa_xstrdup(argv[optind+1]); 2989 port_name = pa_xstrdup(argv[optind+2]); 2990 2991 } else if (pa_streq(argv[optind], "set-default-source")) { 2992 action = SET_DEFAULT_SOURCE; 2993 2994 if (argc != optind+2) { 2995 pa_log(_("You have to specify a source name")); 2996 goto quit; 2997 } 2998 2999 source_name = pa_xstrdup(argv[optind+1]); 3000 3001 } else if (pa_streq(argv[optind], "get-default-source")) { 3002 action = GET_DEFAULT_SOURCE; 3003 3004 } else if (pa_streq(argv[optind], "get-sink-volume")) { 3005 action = GET_SINK_VOLUME; 3006 3007 if (argc < optind+2) { 3008 pa_log(_("You have to specify a sink name/index")); 3009 goto quit; 3010 } 3011 3012 sink_name = pa_xstrdup(argv[optind+1]); 3013 3014 } else if (pa_streq(argv[optind], "set-sink-volume")) { 3015 action = SET_SINK_VOLUME; 3016 3017 if (argc < optind+3) { 3018 pa_log(_("You have to specify a sink name/index and a volume")); 3019 goto quit; 3020 } 3021 3022 sink_name = pa_xstrdup(argv[optind+1]); 3023 3024 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0) 3025 goto quit; 3026 3027 } else if (pa_streq(argv[optind], "get-source-volume")) { 3028 action = GET_SOURCE_VOLUME; 3029 3030 if (argc < optind+2) { 3031 pa_log(_("You have to specify a source name/index")); 3032 goto quit; 3033 } 3034 3035 source_name = pa_xstrdup(argv[optind+1]); 3036 3037 } else if (pa_streq(argv[optind], "set-source-volume")) { 3038 action = SET_SOURCE_VOLUME; 3039 3040 if (argc < optind+3) { 3041 pa_log(_("You have to specify a source name/index and a volume")); 3042 goto quit; 3043 } 3044 3045 source_name = pa_xstrdup(argv[optind+1]); 3046 3047 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0) 3048 goto quit; 3049 3050 } else if (pa_streq(argv[optind], "set-sink-input-volume")) { 3051 action = SET_SINK_INPUT_VOLUME; 3052 3053 if (argc < optind+3) { 3054 pa_log(_("You have to specify a sink input index and a volume")); 3055 goto quit; 3056 } 3057 3058 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) { 3059 pa_log(_("Invalid sink input index")); 3060 goto quit; 3061 } 3062 3063 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0) 3064 goto quit; 3065 3066 } else if (pa_streq(argv[optind], "set-source-output-volume")) { 3067 action = SET_SOURCE_OUTPUT_VOLUME; 3068 3069 if (argc < optind+3) { 3070 pa_log(_("You have to specify a source output index and a volume")); 3071 goto quit; 3072 } 3073 3074 if (pa_atou(argv[optind+1], &source_output_idx) < 0) { 3075 pa_log(_("Invalid source output index")); 3076 goto quit; 3077 } 3078 3079 if (parse_volumes(argv+optind+2, argc-(optind+2)) < 0) 3080 goto quit; 3081 3082 } else if (pa_streq(argv[optind], "get-sink-mute")) { 3083 action = GET_SINK_MUTE; 3084 3085 if (argc < optind+2) { 3086 pa_log(_("You have to specify a sink name/index")); 3087 goto quit; 3088 } 3089 3090 sink_name = pa_xstrdup(argv[optind+1]); 3091 3092 } else if (pa_streq(argv[optind], "set-sink-mute")) { 3093 action = SET_SINK_MUTE; 3094 3095 if (argc != optind+3) { 3096 pa_log(_("You have to specify a sink name/index and a mute action (0, 1, or 'toggle')")); 3097 goto quit; 3098 } 3099 3100 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) { 3101 pa_log(_("Invalid mute specification")); 3102 goto quit; 3103 } 3104 3105 sink_name = pa_xstrdup(argv[optind+1]); 3106 3107 } else if (pa_streq(argv[optind], "get-source-mute")) { 3108 action = GET_SOURCE_MUTE; 3109 3110 if (argc < optind+2) { 3111 pa_log(_("You have to specify a source name/index")); 3112 goto quit; 3113 } 3114 3115 source_name = pa_xstrdup(argv[optind+1]); 3116 3117 } else if (pa_streq(argv[optind], "set-source-mute")) { 3118 action = SET_SOURCE_MUTE; 3119 3120 if (argc != optind+3) { 3121 pa_log(_("You have to specify a source name/index and a mute action (0, 1, or 'toggle')")); 3122 goto quit; 3123 } 3124 3125 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) { 3126 pa_log(_("Invalid mute specification")); 3127 goto quit; 3128 } 3129 3130 source_name = pa_xstrdup(argv[optind+1]); 3131 3132 } else if (pa_streq(argv[optind], "set-sink-input-mute")) { 3133 action = SET_SINK_INPUT_MUTE; 3134 3135 if (argc != optind+3) { 3136 pa_log(_("You have to specify a sink input index and a mute action (0, 1, or 'toggle')")); 3137 goto quit; 3138 } 3139 3140 if (pa_atou(argv[optind+1], &sink_input_idx) < 0) { 3141 pa_log(_("Invalid sink input index specification")); 3142 goto quit; 3143 } 3144 3145 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) { 3146 pa_log(_("Invalid mute specification")); 3147 goto quit; 3148 } 3149 3150 } else if (pa_streq(argv[optind], "set-source-output-mute")) { 3151 action = SET_SOURCE_OUTPUT_MUTE; 3152 3153 if (argc != optind+3) { 3154 pa_log(_("You have to specify a source output index and a mute action (0, 1, or 'toggle')")); 3155 goto quit; 3156 } 3157 3158 if (pa_atou(argv[optind+1], &source_output_idx) < 0) { 3159 pa_log(_("Invalid source output index specification")); 3160 goto quit; 3161 } 3162 3163 if ((mute = parse_mute(argv[optind+2])) == INVALID_MUTE) { 3164 pa_log(_("Invalid mute specification")); 3165 goto quit; 3166 } 3167 3168 } else if (pa_streq(argv[optind], "send-message")) { 3169 action = SEND_MESSAGE; 3170 3171 if (argc < optind+3) { 3172 pa_log(_("You have to specify at least an object path and a message name")); 3173 goto quit; 3174 } 3175 3176 object_path = pa_xstrdup(argv[optind + 1]); 3177 message = pa_xstrdup(argv[optind + 2]); 3178 if (argc >= optind+4) 3179 message_args = pa_xstrdup(argv[optind + 3]); 3180 3181 if (argc > optind+4) 3182 pa_log(_("Excess arguments given, they will be ignored. Note that all message parameters must be given as a single string.")); 3183 3184 } else if (pa_streq(argv[optind], "subscribe")) 3185 3186 action = SUBSCRIBE; 3187 3188 else if (pa_streq(argv[optind], "set-sink-formats")) { 3189 int32_t tmp; 3190 3191 if (argc != optind+3 || pa_atoi(argv[optind+1], &tmp) < 0) { 3192 pa_log(_("You have to specify a sink index and a semicolon-separated list of supported formats")); 3193 goto quit; 3194 } 3195 3196 sink_idx = tmp; 3197 action = SET_SINK_FORMATS; 3198 formats = pa_xstrdup(argv[optind+2]); 3199 3200 } else if (pa_streq(argv[optind], "set-port-latency-offset")) { 3201 action = SET_PORT_LATENCY_OFFSET; 3202 3203 if (argc != optind+4) { 3204 pa_log(_("You have to specify a card name/index, a port name and a latency offset")); 3205 goto quit; 3206 } 3207 3208 card_name = pa_xstrdup(argv[optind+1]); 3209 port_name = pa_xstrdup(argv[optind+2]); 3210 if (pa_atoi(argv[optind + 3], &latency_offset) < 0) { 3211 pa_log(_("Could not parse latency offset")); 3212 goto quit; 3213 } 3214 3215 } else if (pa_streq(argv[optind], "help")) { 3216 help(bn); 3217 ret = 0; 3218 goto quit; 3219 } 3220 } 3221 3222 if (action == NONE) { 3223 pa_log(_("No valid command specified.")); 3224 goto quit; 3225 } 3226 3227 if (!(m = pa_mainloop_new())) { 3228 pa_log(_("pa_mainloop_new() failed.")); 3229 goto quit; 3230 } 3231 3232 mainloop_api = pa_mainloop_get_api(m); 3233 3234 pa_assert_se(pa_signal_init(mainloop_api) == 0); 3235 pa_signal_new(SIGINT, exit_signal_callback, NULL); 3236 pa_signal_new(SIGTERM, exit_signal_callback, NULL); 3237 pa_disable_sigpipe(); 3238 3239 if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) { 3240 pa_log(_("pa_context_new() failed.")); 3241 goto quit; 3242 } 3243 3244 pa_context_set_state_callback(context, context_state_callback, NULL); 3245 if (pa_context_connect(context, server, 0, NULL) < 0) { 3246 pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context))); 3247 goto quit; 3248 } 3249 3250 if (pa_mainloop_run(m, &ret) < 0) { 3251 pa_log(_("pa_mainloop_run() failed.")); 3252 goto quit; 3253 } 3254 3255 if (format == JSON && list_encoder && !pa_json_encoder_is_empty(list_encoder)) { 3256 pa_json_encoder_end_object(list_encoder); 3257 char* list_json_str = pa_json_encoder_to_string_free(list_encoder); 3258 printf("%s", list_json_str); 3259 pa_xfree(list_json_str); 3260 } 3261 3262quit: 3263#ifdef SNDFILE_ENABLE 3264 if (sample_stream) 3265 pa_stream_unref(sample_stream); 3266#endif 3267 if (context) 3268 pa_context_unref(context); 3269 3270 if (m) { 3271 pa_signal_done(); 3272 pa_mainloop_free(m); 3273 } 3274 3275 pa_xfree(server); 3276 pa_xfree(list_type); 3277 pa_xfree(sample_name); 3278 pa_xfree(sink_name); 3279 pa_xfree(source_name); 3280 pa_xfree(module_args); 3281 pa_xfree(card_name); 3282 pa_xfree(profile_name); 3283 pa_xfree(port_name); 3284 pa_xfree(formats); 3285 pa_xfree(object_path); 3286 pa_xfree(message); 3287 pa_xfree(message_args); 3288#ifdef SNDFILE_ENABLE 3289 if (sndfile) 3290 sf_close(sndfile); 3291#endif 3292 if (proplist) 3293 pa_proplist_free(proplist); 3294 3295 return ret; 3296} 3297