xref: /third_party/pulseaudio/src/utils/pacmd.c (revision 53a5a1b3)
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