예제 #1
0
파일: util.c 프로젝트: felfert/pulseaudio
char *pa_get_fqdn(char *s, size_t l) {
    char hn[256];
#ifdef HAVE_GETADDRINFO
    struct addrinfo *a, hints;
#endif

    pa_assert(s);
    pa_assert(l > 0);

    if (!pa_get_host_name(hn, sizeof(hn)))
        return NULL;

#ifdef HAVE_GETADDRINFO
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_flags = AI_CANONNAME;

    if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname)
        return pa_strlcpy(s, hn, l);

    pa_strlcpy(s, a->ai_canonname, l);
    freeaddrinfo(a);
    return s;
#else
    return pa_strlcpy(s, hn, l);
#endif
}
예제 #2
0
파일: util.c 프로젝트: felfert/pulseaudio
char *pa_get_user_name(char *s, size_t l) {
    const char *p;
    char *name = NULL;
#ifdef OS_IS_WIN32
    char buf[1024];
#endif

#ifdef HAVE_PWD_H
    struct passwd *r;
#endif

    pa_assert(s);
    pa_assert(l > 0);

    p = NULL;
#ifdef HAVE_GETUID
    p = getuid() == 0 ? "root" : NULL;
#endif
    if (!p) p = getenv("USER");
    if (!p) p = getenv("LOGNAME");
    if (!p) p = getenv("USERNAME");

    if (p) {
        name = pa_strlcpy(s, p, l);
    } else {
#ifdef HAVE_PWD_H

        if ((r = pa_getpwuid_malloc(getuid())) == NULL) {
            pa_snprintf(s, l, "%lu", (unsigned long) getuid());
            return s;
        }

        name = pa_strlcpy(s, r->pw_name, l);
        pa_getpwuid_free(r);

#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
        DWORD size = sizeof(buf);

        if (!GetUserName(buf, &size)) {
            errno = ENOENT;
            return NULL;
        }

        name = pa_strlcpy(s, buf, l);

#else /* HAVE_PWD_H */

        return NULL;
#endif /* HAVE_PWD_H */
    }

    return name;
}
예제 #3
0
파일: util.c 프로젝트: asceticmt/pulseaudio
char *pa_get_home_dir(char *s, size_t l) {
    char *e;
    char *dir;
#ifdef HAVE_PWD_H
    struct passwd *r;
#endif

    pa_assert(s);
    pa_assert(l > 0);

    if ((e = getenv("HOME"))) {
        dir = pa_strlcpy(s, e, l);
        goto finish;
    }

    if ((e = getenv("USERPROFILE"))) {
        dir = pa_strlcpy(s, e, l);
        goto finish;
    }

#ifdef HAVE_PWD_H
    errno = 0;
    if ((r = pa_getpwuid_malloc(getuid())) == NULL) {
        if (!errno)
            errno = ENOENT;

        return NULL;
    }

    dir = pa_strlcpy(s, r->pw_dir, l);

    pa_getpwuid_free(r);
#endif /* HAVE_PWD_H */

finish:
    if (!dir) {
        errno = ENOENT;
        return NULL;
    }

    if (!pa_is_path_absolute(dir)) {
        pa_log("Failed to get the home directory, not an absolute path: %s", dir);
        errno = ENOENT;
        return NULL;
    }

    return dir;
}
예제 #4
0
파일: util.c 프로젝트: thewb/mokoiax
char *pa_get_user_name(char *s, size_t l) {
    const char *p;
    char buf[1024];

#ifdef HAVE_PWD_H
    struct passwd pw, *r;
#endif

    pa_assert(s);
    pa_assert(l > 0);

    if (!(p = (getuid() == 0 ? "root" : NULL)) &&
            !(p = getenv("USER")) &&
            !(p = getenv("LOGNAME")) &&
            !(p = getenv("USERNAME"))) {
#ifdef HAVE_PWD_H

#ifdef HAVE_GETPWUID_R
        if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
#else
        /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
            * that do not support getpwuid_r. */
        if ((r = getpwuid(getuid())) == NULL) {
#endif
            pa_snprintf(s, l, "%lu", (unsigned long) getuid());
            return s;
        }

        p = r->pw_name;

#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */
        DWORD size = sizeof(buf);

        if (!GetUserName(buf, &size))
            return NULL;

        p = buf;

#else /* HAVE_PWD_H */
        return NULL;
#endif /* HAVE_PWD_H */
    }

    return pa_strlcpy(s, p, l);
}

char *pa_get_host_name(char *s, size_t l) {

    pa_assert(s);
    pa_assert(l > 0);

    if (gethostname(s, l) < 0) {
        pa_log("gethostname(): %s", pa_cstrerror(errno));
        return NULL;
    }

    s[l-1] = 0;
    return s;
}
예제 #5
0
파일: util.c 프로젝트: felfert/pulseaudio
char *pa_get_home_dir(char *s, size_t l) {
    char *e, *dir;

#ifdef HAVE_PWD_H
    struct passwd *r;
#endif

    pa_assert(s);
    pa_assert(l > 0);

    if ((e = getenv("HOME")))
        return pa_strlcpy(s, e, l);

    if ((e = getenv("USERPROFILE")))
        return pa_strlcpy(s, e, l);

#ifdef HAVE_PWD_H
    errno = 0;
    if ((r = pa_getpwuid_malloc(getuid())) == NULL) {
        if (!errno)
            errno = ENOENT;

        return NULL;
    }

    dir = pa_strlcpy(s, r->pw_dir, l);

    pa_getpwuid_free(r);

    return dir;
#else /* HAVE_PWD_H */

    errno = ENOENT;
    return NULL;
#endif
}
예제 #6
0
pa_socket_server* pa_socket_server_new_unix(pa_mainloop_api *m, const char *filename) {
    int fd = -1;
    struct sockaddr_un sa;
    pa_socket_server *s;

    pa_assert(m);
    pa_assert(filename);

    if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
        pa_log("socket(): %s", pa_cstrerror(errno));
        goto fail;
    }

    memset(&sa, 0, sizeof(sa));
    sa.sun_family = AF_UNIX;
    pa_strlcpy(sa.sun_path, filename, sizeof(sa.sun_path));

    pa_make_socket_low_delay(fd);

    if (bind(fd, (struct sockaddr*) &sa, (socklen_t) SUN_LEN(&sa)) < 0) {
        pa_log("bind(): %s", pa_cstrerror(errno));
        goto fail;
    }

    /* Allow access from all clients. Sockets like this one should
     * always be put inside a directory with proper access rights,
     * because not all OS check the access rights on the socket
     * inodes. */
    chmod(filename, 0777);

    if (listen(fd, 5) < 0) {
        pa_log("listen(): %s", pa_cstrerror(errno));
        goto fail;
    }

    pa_assert_se(s = pa_socket_server_new(m, fd));

    s->filename = pa_xstrdup(filename);
    s->type = SOCKET_SERVER_UNIX;

    return s;

fail:
    if (fd >= 0)
        pa_close(fd);

    return NULL;
}
예제 #7
0
pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
    uint16_t port = 0;
    bool ss_valid = false;

    pa_assert(t);
    pa_assert(i);

    i->origin = i->session_name = NULL;
    i->salen = 0;
    i->payload = 255;

    if (!pa_startswith(t, PA_SDP_HEADER)) {
        pa_log("Failed to parse SDP data: invalid header.");
        goto fail;
    }

    t += sizeof(PA_SDP_HEADER)-1;

    while (*t) {
        size_t l;

        l = strcspn(t, "\n");

        if (l <= 2) {
            pa_log("Failed to parse SDP data: line too short: >%s<.", t);
            goto fail;
        }

        if (pa_startswith(t, "o="))
            i->origin = pa_xstrndup(t+2, l-2);
        else if (pa_startswith(t, "s="))
            i->session_name = pa_xstrndup(t+2, l-2);
        else if (pa_startswith(t, "c=IN IP4 ")) {
            char a[64];
            size_t k;

            k = l-8 > sizeof(a) ? sizeof(a) : l-8;

            pa_strlcpy(a, t+9, k);
            a[strcspn(a, "/")] = 0;

            if (inet_pton(AF_INET, a, &((struct sockaddr_in*) &i->sa)->sin_addr) <= 0) {
                pa_log("Failed to parse SDP data: bad address: >%s<.", a);
                goto fail;
            }

            ((struct sockaddr_in*) &i->sa)->sin_family = AF_INET;
            ((struct sockaddr_in*) &i->sa)->sin_port = 0;
            i->salen = sizeof(struct sockaddr_in);
#ifdef HAVE_IPV6
        } else if (pa_startswith(t, "c=IN IP6 ")) {
            char a[64];
            size_t k;

            k = l-8 > sizeof(a) ? sizeof(a) : l-8;

            pa_strlcpy(a, t+9, k);
            a[strcspn(a, "/")] = 0;

            if (inet_pton(AF_INET6, a, &((struct sockaddr_in6*) &i->sa)->sin6_addr) <= 0) {
                pa_log("Failed to parse SDP data: bad address: >%s<.", a);
                goto fail;
            }

            ((struct sockaddr_in6*) &i->sa)->sin6_family = AF_INET6;
            ((struct sockaddr_in6*) &i->sa)->sin6_port = 0;
            i->salen = sizeof(struct sockaddr_in6);
#endif
        } else if (pa_startswith(t, "m=audio ")) {

            if (i->payload > 127) {
                int _port, _payload;

                if (sscanf(t+8, "%i RTP/AVP %i", &_port, &_payload) == 2) {

                    if (_port <= 0 || _port > 0xFFFF) {
                        pa_log("Failed to parse SDP data: invalid port %i.", _port);
                        goto fail;
                    }

                    if (_payload < 0 || _payload > 127) {
                        pa_log("Failed to parse SDP data: invalid payload %i.", _payload);
                        goto fail;
                    }

                    port = (uint16_t) _port;
                    i->payload = (uint8_t) _payload;

                    if (pa_rtp_sample_spec_from_payload(i->payload, &i->sample_spec))
                        ss_valid = true;
                }
            }
        } else if (pa_startswith(t, "a=rtpmap:")) {

            if (i->payload <= 127) {
                char c[64];
                int _payload;

                if (sscanf(t+9, "%i %64c", &_payload, c) == 2) {

                    if (_payload < 0 || _payload > 127) {
                        pa_log("Failed to parse SDP data: invalid payload %i.", _payload);
                        goto fail;
                    }
                    if (_payload == i->payload) {

                        c[strcspn(c, "\n")] = 0;

                        if (parse_sdp_sample_spec(&i->sample_spec, c))
                            ss_valid = true;
                    }
                }
            }
        }

        t += l;

        if (*t == '\n')
            t++;
    }

    if (!i->origin || (!is_goodbye && (!i->salen || i->payload > 127 || !ss_valid || port == 0))) {
        pa_log("Failed to parse SDP data: missing data.");
        goto fail;
    }

    if (((struct sockaddr*) &i->sa)->sa_family == AF_INET)
        ((struct sockaddr_in*) &i->sa)->sin_port = htons(port);
    else
        ((struct sockaddr_in6*) &i->sa)->sin6_port = htons(port);

    return i;

fail:
    pa_xfree(i->origin);
    pa_xfree(i->session_name);

    return NULL;
}
예제 #8
0
파일: util.c 프로젝트: felfert/pulseaudio
char *pa_get_binary_name(char *s, size_t l) {

    pa_assert(s);
    pa_assert(l > 0);

#if defined(OS_IS_WIN32)
    {
        char path[PATH_MAX];

        if (GetModuleFileName(NULL, path, PATH_MAX))
            return pa_strlcpy(s, pa_path_get_filename(path), l);
    }
#endif

#ifdef __linux__
    {
        char *rp;
        /* This works on Linux only */

        if ((rp = pa_readlink("/proc/self/exe"))) {
            pa_strlcpy(s, pa_path_get_filename(rp), l);
            pa_xfree(rp);
            return s;
        }
    }
#endif

#ifdef __FreeBSD__
    {
        char *rp;

        if ((rp = pa_readlink("/proc/curproc/file"))) {
            pa_strlcpy(s, pa_path_get_filename(rp), l);
            pa_xfree(rp);
            return s;
        }
    }
#endif

#if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME)
    {

        #ifndef TASK_COMM_LEN
        /* Actually defined in linux/sched.h */
        #define TASK_COMM_LEN 16
        #endif

        char tcomm[TASK_COMM_LEN+1];
        memset(tcomm, 0, sizeof(tcomm));

        /* This works on Linux only */
        if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0)
            return pa_strlcpy(s, tcomm, l);

    }
#endif

#ifdef OS_IS_DARWIN
    {
        int mib[] = { CTL_KERN, KERN_PROCARGS, getpid(), 0 };
        size_t len, nmib = (sizeof(mib) / sizeof(mib[0])) - 1;
        char *buf;

        sysctl(mib, nmib, NULL, &len, NULL, 0);
        buf = (char *) pa_xmalloc(len);

        if (sysctl(mib, nmib, buf, &len, NULL, 0) == 0) {
            pa_strlcpy(s, basename(buf), l);
            pa_xfree(buf);
            return s;
        }

        pa_xfree(buf);

        /* fall thru */
    }
#endif /* OS_IS_DARWIN */

    errno = ENOENT;
    return NULL;
}
예제 #9
0
static int handle_response(struct userdata *u) {
    pa_assert(u);

    switch (u->state) {

        case STATE_AUTH:
            pa_assert(u->read_length == sizeof(int32_t));

            /* Process auth data */
            if (!*(int32_t*) u->read_data) {
                pa_log("Authentication failed: %s", pa_cstrerror(errno));
                return -1;
            }

            /* Request latency data */
            pa_assert(!u->write_data);
            *(int32_t*) (u->write_data = pa_xmalloc(u->write_length = sizeof(int32_t))) = ESD_PROTO_LATENCY;

            u->write_index = 0;
            u->state = STATE_LATENCY;

            /* Space for next response */
            pa_assert(u->read_length >= sizeof(int32_t));
            u->read_index = 0;
            u->read_length = sizeof(int32_t);

            break;

        case STATE_LATENCY: {
            int32_t *p;
            pa_assert(u->read_length == sizeof(int32_t));

            /* Process latency info */
            u->latency = (pa_usec_t) ((double) (*(int32_t*) u->read_data) * 1000000 / 44100);
            if (u->latency > 10000000) {
                pa_log_warn("Invalid latency information received from server");
                u->latency = 0;
            }

            /* Create stream */
            pa_assert(!u->write_data);
            p = u->write_data = pa_xmalloc0(u->write_length = sizeof(int32_t)*3+ESD_NAME_MAX);
            *(p++) = ESD_PROTO_STREAM_PLAY;
            *(p++) = u->format;
            *(p++) = u->rate;
            pa_strlcpy((char*) p, "PulseAudio Tunnel", ESD_NAME_MAX);

            u->write_index = 0;
            u->state = STATE_PREPARE;

            /* Don't read any further */
            pa_xfree(u->read_data);
            u->read_data = NULL;
            u->read_index = u->read_length = 0;

            break;
        }

        default:
            pa_assert_not_reached();
    }

    return 0;
}
예제 #10
0
파일: util.c 프로젝트: thewb/mokoiax
char *pa_get_home_dir(char *s, size_t l) {
    char *e;

#ifdef HAVE_PWD_H
    char buf[1024];
    struct passwd pw, *r;
#endif

    pa_assert(s);
    pa_assert(l > 0);

    if ((e = getenv("HOME")))
        return pa_strlcpy(s, e, l);

    if ((e = getenv("USERPROFILE")))
        return pa_strlcpy(s, e, l);

#ifdef HAVE_PWD_H
#ifdef HAVE_GETPWUID_R
    if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) {
        pa_log("getpwuid_r() failed");
#else
    /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X)
        * that do not support getpwuid_r. */
    if ((r = getpwuid(getuid())) == NULL) {
        pa_log("getpwuid_r() failed");
#endif
        return NULL;
    }

    return pa_strlcpy(s, r->pw_dir, l);
#else /* HAVE_PWD_H */
    return NULL;
#endif
}

char *pa_get_binary_name(char *s, size_t l) {

    pa_assert(s);
    pa_assert(l > 0);

#if defined(OS_IS_WIN32)
    {
        char path[PATH_MAX];

        if (GetModuleFileName(NULL, path, PATH_MAX))
            return pa_strlcpy(s, pa_path_get_filename(path), l);
    }
#endif

#ifdef __linux__
    {
        char *rp;
        /* This works on Linux only */

        if ((rp = pa_readlink("/proc/self/exe"))) {
            pa_strlcpy(s, pa_path_get_filename(rp), l);
            pa_xfree(rp);
            return s;
        }
    }

#endif

#if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_NAME)
    {

#ifndef TASK_COMM_LEN
        /* Actually defined in linux/sched.h */
#define TASK_COMM_LEN 16
#endif

        char tcomm[TASK_COMM_LEN+1];
        memset(tcomm, 0, sizeof(tcomm));

        /* This works on Linux only */
        if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0)
            return pa_strlcpy(s, tcomm, l);

    }
#endif

    return NULL;
}
예제 #11
0
int main(int argc, char*argv[]) {
    pid_t pid;
    int fd = -1;
    int ret = 1, i;
    struct sockaddr_un sa;
    char *ibuf = NULL;
    char *obuf = NULL;
    size_t buf_size, ibuf_size, ibuf_index, ibuf_length, obuf_size, obuf_index, obuf_length;
    char *cli;
    bool ibuf_eof, obuf_eof, ibuf_closed, obuf_closed;
    struct pollfd pollfd[3];
    struct pollfd *watch_socket, *watch_stdin, *watch_stdout;
    int stdin_type = 0, stdout_type = 0, fd_type = 0;

    char *bn = NULL;
    int c;

    static const struct option long_options[] = {
        {"version",     0, NULL, ARG_VERSION},
        {"help",        0, NULL, 'h'},
        {NULL,          0, NULL, 0}
    };

    setlocale(LC_ALL, "");
#ifdef ENABLE_NLS
    bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
#endif

    bn = pa_path_get_filename(argv[0]);

    while ((c = getopt_long(argc, argv, "h", long_options, NULL)) != -1) {
        switch (c) {
            case 'h' :
                help(bn);
                ret = 0;
                goto quit;
            case ARG_VERSION:
                printf(_("pacmd %s\n"
                         "Compiled with libpulse %s\n"
                         "Linked with libpulse %s\n"),
                       PACKAGE_VERSION,
                       pa_get_headers_version(),
                       pa_get_library_version());
                ret = 0;
                goto quit;
            default:
                goto quit;
        }
    }

    if (pa_pid_file_check_running(&pid, "pulseaudio") < 0) {
        pa_log(_("No PulseAudio daemon running, or not running as session daemon."));
        goto quit;
    }

    if ((fd = pa_socket_cloexec(PF_UNIX, SOCK_STREAM, 0)) < 0) {
        pa_log(_("socket(PF_UNIX, SOCK_STREAM, 0): %s"), strerror(errno));
        goto quit;
    }

    pa_zero(sa);
    sa.sun_family = AF_UNIX;

    if (!(cli = pa_runtime_path("cli")))
        goto quit;

    pa_strlcpy(sa.sun_path, cli, sizeof(sa.sun_path));
    pa_xfree(cli);

    for (i = 0; i < 5; i++) {
        int r;

        if ((r = connect(fd, (struct sockaddr*) &sa, sizeof(sa))) < 0 && (errno != ECONNREFUSED && errno != ENOENT)) {
            pa_log(_("connect(): %s"), strerror(errno));
            goto quit;
        }

        if (r >= 0)
            break;

        if (pa_pid_file_kill(SIGUSR2, NULL, "pulseaudio") < 0) {
            pa_log(_("Failed to kill PulseAudio daemon."));
            goto quit;
        }

        pa_msleep(300);
    }

    if (i >= 5) {
        pa_log(_("Daemon not responding."));
        goto quit;
    }

    buf_size = pa_pipe_buf(fd);
    ibuf_size = PA_MIN(buf_size, pa_pipe_buf(STDIN_FILENO));
    ibuf = pa_xmalloc(ibuf_size);
    obuf_size = PA_MIN(buf_size, pa_pipe_buf(STDOUT_FILENO));
    obuf = pa_xmalloc(obuf_size);
    ibuf_index = ibuf_length = obuf_index = obuf_length = 0;
    ibuf_eof = obuf_eof = ibuf_closed = obuf_closed = false;

    if (argc > 1) {
        for (i = 1; i < argc; i++) {
            size_t k;

            k = PA_MIN(ibuf_size - ibuf_length, strlen(argv[i]));
            memcpy(ibuf + ibuf_length, argv[i], k);
            ibuf_length += k;

            if (ibuf_length < ibuf_size) {
                ibuf[ibuf_length] = i < argc-1 ? ' ' : '\n';
                ibuf_length++;
            }
        }

        ibuf_eof = true;
    }

    if (!ibuf_eof && isatty(STDIN_FILENO)) {
        /* send hello to enable interactive mode (welcome message, prompt) */
        if (pa_write(fd, "hello\n", 6, &fd_type) < 0) {
            pa_log(_("write(): %s"), strerror(errno));
            goto quit;
        }
    }

    for (;;) {
        struct pollfd *p;

        if (ibuf_eof &&
            obuf_eof &&
            ibuf_length <= 0 &&
            obuf_length <= 0)
            break;

        if (ibuf_length <= 0 && ibuf_eof && !ibuf_closed) {
            shutdown(fd, SHUT_WR);
            ibuf_closed = true;
        }

        if (obuf_length <= 0 && obuf_eof && !obuf_closed) {
            shutdown(fd, SHUT_RD);
            obuf_closed = true;
        }

        pa_zero(pollfd);

        p = pollfd;

        if (ibuf_length > 0 || (!obuf_eof && obuf_length <= 0)) {
            watch_socket = p++;
            watch_socket->fd = fd;
            watch_socket->events =
                (ibuf_length > 0 ? POLLOUT : 0) |
                (!obuf_eof && obuf_length <= 0 ? POLLIN : 0);
        } else
            watch_socket = NULL;

        if (!ibuf_eof && ibuf_length <= 0) {
            watch_stdin = p++;
            watch_stdin->fd = STDIN_FILENO;
            watch_stdin->events = POLLIN;
        } else
            watch_stdin = NULL;

        if (obuf_length > 0) {
            watch_stdout = p++;
            watch_stdout->fd = STDOUT_FILENO;
            watch_stdout->events = POLLOUT;
        } else
            watch_stdout = NULL;

        if (pa_poll(pollfd, p-pollfd, -1) < 0) {

            if (errno == EINTR)
                continue;

            pa_log(_("poll(): %s"), strerror(errno));
            goto quit;
        }

        if (watch_stdin) {
            if (watch_stdin->revents & POLLIN) {
                ssize_t r;
                pa_assert(ibuf_length <= 0);

                if ((r = pa_read(STDIN_FILENO, ibuf, ibuf_size, &stdin_type)) <= 0) {
                    if (r < 0) {
                        pa_log(_("read(): %s"), strerror(errno));
                        goto quit;
                    }

                    ibuf_eof = true;
                } else {
                    ibuf_length = (size_t) r;
                    ibuf_index = 0;
                }
            } else if (watch_stdin->revents & POLLHUP)
                ibuf_eof = true;
        }

        if (watch_socket) {
            if (watch_socket->revents & POLLIN) {
                ssize_t r;
                pa_assert(obuf_length <= 0);

                if ((r = pa_read(fd, obuf, obuf_size, &fd_type)) <= 0) {
                    if (r < 0) {
                        pa_log(_("read(): %s"), strerror(errno));
                        goto quit;
                    }

                    obuf_eof = true;
                } else {
                    obuf_length = (size_t) r;
                    obuf_index = 0;
                }
            } else if (watch_socket->revents & POLLHUP)
                obuf_eof = true;
        }

        if (watch_stdout) {
            if (watch_stdout->revents & POLLHUP) {
                obuf_eof = true;
                obuf_length = 0;
            } else if (watch_stdout->revents & POLLOUT) {
                ssize_t r;
                pa_assert(obuf_length > 0);

                if ((r = pa_write(STDOUT_FILENO, obuf + obuf_index, obuf_length, &stdout_type)) < 0) {
                    pa_log(_("write(): %s"), strerror(errno));
                    goto quit;
                }

                obuf_length -= (size_t) r;
                obuf_index += obuf_index;
            }
        }

        if (watch_socket) {
            if (watch_socket->revents & POLLHUP) {
                ibuf_eof = true;
                ibuf_length = 0;
            } if (watch_socket->revents & POLLOUT) {
                ssize_t r;
                pa_assert(ibuf_length > 0);

                if ((r = pa_write(fd, ibuf + ibuf_index, ibuf_length, &fd_type)) < 0) {
                    pa_log(_("write(): %s"), strerror(errno));
                    goto quit;
                }

                ibuf_length -= (size_t) r;
                ibuf_index += obuf_index;
            }
        }
    }

    ret = 0;

quit:
    if (fd >= 0)
        pa_close(fd);

    pa_xfree(obuf);
    pa_xfree(ibuf);

    return ret;
}
예제 #12
0
static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
    struct userdata *u = userdata;
    struct entry entry, *old;
    char *name;
    pa_datum key, data;

    pa_assert(c);
    pa_assert(u);

    if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
        t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
        t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
        t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
        return;

    pa_zero(entry);
    entry.version = ENTRY_VERSION;

    if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
        pa_sink *sink;

        if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
            return;

        name = pa_sprintf_malloc("sink:%s", sink->name);

        if ((old = read_entry(u, name)))
            entry = *old;

        if (sink->save_volume) {
            entry.channel_map = sink->channel_map;
            entry.volume = *pa_sink_get_volume(sink, FALSE);
            entry.volume_valid = TRUE;
        }

        if (sink->save_muted) {
            entry.muted = pa_sink_get_mute(sink, FALSE);
            entry.muted_valid = TRUE;
        }

        if (sink->save_port) {
            pa_strlcpy(entry.port, sink->active_port ? sink->active_port->name : "", sizeof(entry.port));
            entry.port_valid = TRUE;
        }

    } else {
        pa_source *source;

        pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);

        if (!(source = pa_idxset_get_by_index(c->sources, idx)))
            return;

        name = pa_sprintf_malloc("source:%s", source->name);

        if ((old = read_entry(u, name)))
            entry = *old;

        if (source->save_volume) {
            entry.channel_map = source->channel_map;
            entry.volume = *pa_source_get_volume(source, FALSE);
            entry.volume_valid = TRUE;
        }

        if (source->save_muted) {
            entry.muted = pa_source_get_mute(source, FALSE);
            entry.muted_valid = TRUE;
        }

        if (source->save_port) {
            pa_strlcpy(entry.port, source->active_port ? source->active_port->name : "", sizeof(entry.port));
            entry.port_valid = TRUE;
        }
    }

    if (old) {

        if (entries_equal(old, &entry)) {
            pa_xfree(old);
            pa_xfree(name);
            return;
        }

        pa_xfree(old);
    }

    key.data = name;
    key.size = strlen(name);

    data.data = &entry;
    data.size = sizeof(entry);

    pa_log_info("Storing volume/mute/port for device %s.", name);

    pa_database_set(u->database, &key, &data, TRUE);

    pa_xfree(name);

    trigger_save(u);
}