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 <assert.h> 25#include <signal.h> 26#include <sys/socket.h> 27#include <unistd.h> 28#include <errno.h> 29#include <string.h> 30#include <sys/un.h> 31#include <getopt.h> 32#include <locale.h> 33 34#include <pulse/util.h> 35#include <pulse/xmalloc.h> 36 37#include <pulsecore/i18n.h> 38#include <pulsecore/poll.h> 39#include <pulsecore/macro.h> 40#include <pulsecore/core-util.h> 41#include <pulsecore/log.h> 42#include <pulsecore/pid.h> 43 44static void help(const char *argv0) { 45 printf("%s %s\n", argv0, "exit"); 46 printf("%s %s\n", argv0, "help"); 47 printf("%s %s\n", argv0, "list-(modules|sinks|sources|clients|cards|samples)"); 48 printf("%s %s\n", argv0, "list-(sink-inputs|source-outputs)"); 49 printf("%s %s\n", argv0, "stat"); 50 printf("%s %s\n", argv0, "info"); 51 printf("%s %s %s\n", argv0, "load-module", _("NAME [ARGS ...]")); 52 printf("%s %s %s\n", argv0, "unload-module", _("NAME|#N")); 53 printf("%s %s %s\n", argv0, "describe-module", _("NAME")); 54 printf("%s %s %s\n", argv0, "set-(sink|source)-volume", _("NAME|#N VOLUME")); 55 printf("%s %s %s\n", argv0, "set-(sink-input|source-output)-volume", _("#N VOLUME")); 56 printf("%s %s %s\n", argv0, "set-(sink|source)-mute", _("NAME|#N 1|0")); 57 printf("%s %s %s\n", argv0, "set-(sink-input|source-output)-mute", _("#N 1|0")); 58 printf("%s %s %s\n", argv0, "update-(sink|source)-proplist", _("NAME|#N KEY=VALUE")); 59 printf("%s %s %s\n", argv0, "update-(sink-input|source-output)-proplist", _("#N KEY=VALUE")); 60 printf("%s %s %s\n", argv0, "set-default-(sink|source)", _("NAME|#N")); 61 printf("%s %s %s\n", argv0, "kill-(client|sink-input|source-output)", _("#N")); 62 printf("%s %s %s\n", argv0, "play-sample", _("NAME SINK|#N")); 63 printf("%s %s %s\n", argv0, "remove-sample", _("NAME")); 64 printf("%s %s %s\n", argv0, "load-sample", _("NAME FILENAME")); 65 printf("%s %s %s\n", argv0, "load-sample-lazy", _("NAME FILENAME")); 66 printf("%s %s %s\n", argv0, "load-sample-dir-lazy", _("PATHNAME")); 67 printf("%s %s %s\n", argv0, "play-file", _("FILENAME SINK|#N")); 68 printf("%s %s\n", argv0, "dump"); 69 printf("%s %s %s\n", argv0, "move-(sink-input|source-output)", _("#N SINK|SOURCE")); 70 printf("%s %s %s\n", argv0, "suspend-(sink|source)", _("NAME|#N 1|0")); 71 printf("%s %s %s\n", argv0, "suspend", _("1|0")); 72 printf("%s %s %s\n", argv0, "set-card-profile", _("CARD PROFILE")); 73 printf("%s %s %s\n", argv0, "set-(sink|source)-port", _("NAME|#N PORT")); 74 printf("%s %s %s\n", argv0, "set-port-latency-offset", _("CARD-NAME|CARD-#N PORT OFFSET")); 75 printf("%s %s %s\n", argv0, "set-log-target", _("TARGET")); 76 printf("%s %s %s\n", argv0, "set-log-level", _("NUMERIC-LEVEL")); 77 printf("%s %s %s\n", argv0, "set-log-meta", _("1|0")); 78 printf("%s %s %s\n", argv0, "set-log-time", _("1|0")); 79 printf("%s %s %s\n", argv0, "set-log-backtrace", _("FRAMES")); 80 printf("%s %s %s\n", argv0, "send-message", _("RECIPIENT MESSAGE [MESSAGE_PARAMETERS]")); 81 82 printf(_("\n" 83 " -h, --help Show this help\n" 84 " --version Show version\n" 85 "When no command is given pacmd starts in the interactive mode.\n" )); 86} 87 88enum { 89 ARG_VERSION = 256 90}; 91 92int main(int argc, char*argv[]) { 93 pid_t pid; 94 int fd = -1; 95 int ret = 1, i; 96 struct sockaddr_un sa; 97 char *ibuf = NULL; 98 char *obuf = NULL; 99 size_t buf_size, ibuf_size, ibuf_index, ibuf_length, obuf_size, obuf_index, obuf_length; 100 char *cli; 101 bool ibuf_eof, obuf_eof, ibuf_closed, obuf_closed; 102 struct pollfd pollfd[3]; 103 struct pollfd *watch_socket, *watch_stdin, *watch_stdout; 104 int stdin_type = 0, stdout_type = 0, fd_type = 0; 105 106 char *bn = NULL; 107 int c; 108 109 static const struct option long_options[] = { 110 {"version", 0, NULL, ARG_VERSION}, 111 {"help", 0, NULL, 'h'}, 112 {NULL, 0, NULL, 0} 113 }; 114 115 setlocale(LC_ALL, ""); 116#ifdef ENABLE_NLS 117 bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); 118#endif 119 120 bn = pa_path_get_filename(argv[0]); 121 122 while ((c = getopt_long(argc, argv, "h", long_options, NULL)) != -1) { 123 switch (c) { 124 case 'h' : 125 help(bn); 126 ret = 0; 127 goto quit; 128 case ARG_VERSION: 129 printf(_("pacmd %s\n" 130 "Compiled with libpulse %s\n" 131 "Linked with libpulse %s\n"), 132 PACKAGE_VERSION, 133 pa_get_headers_version(), 134 pa_get_library_version()); 135 ret = 0; 136 goto quit; 137 default: 138 goto quit; 139 } 140 } 141 142 if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) { 143 pa_log(_("No PulseAudio daemon running, or not running as session daemon.")); 144 goto quit; 145 } 146 147 if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) { 148 pa_log(_("socket(PF_UNIX, SOCK_STREAM, 0): %s"), strerror(errno)); 149 goto quit; 150 } 151 152 pa_zero(sa); 153 sa.sun_family = AF_UNIX; 154 155 if (!(cli = pa_runtime_path("cli"))) 156 goto quit; 157 158 pa_strlcpy(sa.sun_path, cli, sizeof(sa.sun_path)); 159 pa_xfree(cli); 160 161 for (i = 0; i < 5; i++) { 162 int r; 163 164 if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) { 165 pa_log(_("connect(): %s"), strerror(errno)); 166 goto quit; 167 } 168 169 if (r >= 0) 170 break; 171 172 if (pa_pid_file_kill(SIGUSR2, NULL, "pulseaudio") < 0) { 173 pa_log(_("Failed to kill PulseAudio daemon.")); 174 goto quit; 175 } 176 177 pa_msleep(300); 178 } 179 180 if (i >= 5) { 181 pa_log(_("Daemon not responding.")); 182 goto quit; 183 } 184 185 buf_size = pa_pipe_buf(fd); 186 ibuf_size = PA_MIN(buf_size, pa_pipe_buf(STDIN_FILENO)); 187 ibuf = pa_xmalloc(ibuf_size); 188 obuf_size = PA_MIN(buf_size, pa_pipe_buf(STDOUT_FILENO)); 189 obuf = pa_xmalloc(obuf_size); 190 ibuf_index = ibuf_length = obuf_index = obuf_length = 0; 191 ibuf_eof = obuf_eof = ibuf_closed = obuf_closed = false; 192 193 if (argc > 1) { 194 for (i = 1; i < argc; i++) { 195 size_t k; 196 197 k = PA_MIN(ibuf_size - ibuf_length, strlen(argv[i])); 198 memcpy(ibuf + ibuf_length, argv[i], k); 199 ibuf_length += k; 200 201 if (ibuf_length < ibuf_size) { 202 ibuf[ibuf_length] = i < argc-1 ? ' ' : '\n'; 203 ibuf_length++; 204 } 205 } 206 207 ibuf_eof = true; 208 } 209 210 if (!ibuf_eof && isatty(STDIN_FILENO)) { 211 /* send hello to enable interactive mode (welcome message, prompt) */ 212 if (pa_write(fd, "hello\n", 6, &fd_type) < 0) { 213 pa_log(_("write(): %s"), strerror(errno)); 214 goto quit; 215 } 216 } 217 218 for (;;) { 219 struct pollfd *p; 220 221 if (ibuf_eof && 222 obuf_eof && 223 ibuf_length <= 0 && 224 obuf_length <= 0) 225 break; 226 227 if (ibuf_length <= 0 && ibuf_eof && !ibuf_closed) { 228 shutdown(fd, SHUT_WR); 229 ibuf_closed = true; 230 } 231 232 if (obuf_length <= 0 && obuf_eof && !obuf_closed) { 233 shutdown(fd, SHUT_RD); 234 obuf_closed = true; 235 } 236 237 pa_zero(pollfd); 238 239 p = pollfd; 240 241 if (ibuf_length > 0 || (!obuf_eof && obuf_length <= 0)) { 242 watch_socket = p++; 243 watch_socket->fd = fd; 244 watch_socket->events = 245 (ibuf_length > 0 ? POLLOUT : 0) | 246 (!obuf_eof && obuf_length <= 0 ? POLLIN : 0); 247 } else 248 watch_socket = NULL; 249 250 if (!ibuf_eof && ibuf_length <= 0) { 251 watch_stdin = p++; 252 watch_stdin->fd = STDIN_FILENO; 253 watch_stdin->events = POLLIN; 254 } else 255 watch_stdin = NULL; 256 257 if (obuf_length > 0) { 258 watch_stdout = p++; 259 watch_stdout->fd = STDOUT_FILENO; 260 watch_stdout->events = POLLOUT; 261 } else 262 watch_stdout = NULL; 263 264 if (pa_poll(pollfd, p-pollfd, -1) < 0) { 265 266 if (errno == EINTR) 267 continue; 268 269 pa_log(_("poll(): %s"), strerror(errno)); 270 goto quit; 271 } 272 273 if (watch_stdin) { 274 if (watch_stdin->revents & POLLIN) { 275 ssize_t r; 276 pa_assert(ibuf_length <= 0); 277 278 if ((r = pa_read(STDIN_FILENO, ibuf, ibuf_size, &stdin_type)) <= 0) { 279 if (r < 0) { 280 pa_log(_("read(): %s"), strerror(errno)); 281 goto quit; 282 } 283 284 ibuf_eof = true; 285 } else { 286 ibuf_length = (size_t) r; 287 ibuf_index = 0; 288 } 289 } else if (watch_stdin->revents & POLLHUP) 290 ibuf_eof = true; 291 } 292 293 if (watch_socket) { 294 if (watch_socket->revents & POLLIN) { 295 ssize_t r; 296 pa_assert(obuf_length <= 0); 297 298 if ((r = pa_read(fd, obuf, obuf_size, &fd_type)) <= 0) { 299 if (r < 0) { 300 pa_log(_("read(): %s"), strerror(errno)); 301 goto quit; 302 } 303 304 obuf_eof = true; 305 } else { 306 obuf_length = (size_t) r; 307 obuf_index = 0; 308 } 309 } else if (watch_socket->revents & POLLHUP) 310 obuf_eof = true; 311 } 312 313 if (watch_stdout) { 314 if (watch_stdout->revents & POLLHUP) { 315 obuf_eof = true; 316 obuf_length = 0; 317 } else if (watch_stdout->revents & POLLOUT) { 318 ssize_t r; 319 pa_assert(obuf_length > 0); 320 321 if ((r = pa_write(STDOUT_FILENO, obuf + obuf_index, obuf_length, &stdout_type)) < 0) { 322 pa_log(_("write(): %s"), strerror(errno)); 323 goto quit; 324 } 325 326 obuf_length -= (size_t) r; 327 obuf_index += obuf_index; 328 } 329 } 330 331 if (watch_socket) { 332 if (watch_socket->revents & POLLHUP) { 333 ibuf_eof = true; 334 ibuf_length = 0; 335 } else if (watch_socket->revents & POLLOUT) { 336 ssize_t r; 337 pa_assert(ibuf_length > 0); 338 339 if ((r = pa_write(fd, ibuf + ibuf_index, ibuf_length, &fd_type)) < 0) { 340 pa_log(_("write(): %s"), strerror(errno)); 341 goto quit; 342 } 343 344 ibuf_length -= (size_t) r; 345 ibuf_index += obuf_index; 346 } 347 } 348 } 349 350 ret = 0; 351 352quit: 353 if (fd >= 0) 354 pa_close(fd); 355 356 pa_xfree(obuf); 357 pa_xfree(ibuf); 358 359 return ret; 360} 361