Exemplo n.º 1
0
static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) {
    unsigned rate, channels;
    pa_assert(ss);
    pa_assert(c);

    if (pa_startswith(c, "L16/")) {
        ss->format = PA_SAMPLE_S16BE;
        c += 4;
    } else if (pa_startswith(c, "L8/")) {
        ss->format = PA_SAMPLE_U8;
        c += 3;
    } else if (pa_startswith(c, "PCMA/")) {
        ss->format = PA_SAMPLE_ALAW;
        c += 5;
    } else if (pa_startswith(c, "PCMU/")) {
        ss->format = PA_SAMPLE_ULAW;
        c += 5;
    } else
        return NULL;

    if (sscanf(c, "%u/%u", &rate, &channels) == 2) {
        ss->rate = (uint32_t) rate;
        ss->channels = (uint8_t) channels;
    } else if (sscanf(c, "%u", &rate) == 2) {
        ss->rate = (uint32_t) rate;
        ss->channels = 1;
    } else
        return NULL;

    if (!pa_sample_spec_valid(ss))
        return NULL;

    return ss;
}
Exemplo n.º 2
0
int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) {
    uint32_t u;
    pa_assert(c);
    pa_assert(string);

    if (pa_atou(string, &u) >= 0) {
        if (u >= PA_LOG_LEVEL_MAX)
            return -1;

        c->log_level = (pa_log_level_t) u;
    } else if (pa_startswith(string, "debug"))
        c->log_level = PA_LOG_DEBUG;
    else if (pa_startswith(string, "info"))
        c->log_level = PA_LOG_INFO;
    else if (pa_startswith(string, "notice"))
        c->log_level = PA_LOG_NOTICE;
    else if (pa_startswith(string, "warn"))
        c->log_level = PA_LOG_WARN;
    else if (pa_startswith(string, "err"))
        c->log_level = PA_LOG_ERROR;
    else
        return -1;

    return 0;
}
Exemplo n.º 3
0
int pa_parse_address(const char *name, pa_parsed_address *ret_p) {
    const char *p;

    pa_assert(name);
    pa_assert(ret_p);

    memset(ret_p, 0, sizeof(pa_parsed_address));
    ret_p->type = PA_PARSED_ADDRESS_TCP_AUTO;

    if (*name == '{') {
        char *id, *pfx;

        /* The URL starts with a host id for detecting local connections */
        if (!(id = pa_machine_id()))
            return -1;

        pfx = pa_sprintf_malloc("{%s}", id);
        pa_xfree(id);

        if (!pa_startswith(name, pfx)) {
            pa_xfree(pfx);
            /* Not local */
            return -1;
        }

        p = name + strlen(pfx);
        pa_xfree(pfx);
    } else
        p = name;

    if (*p == '/')
        ret_p->type = PA_PARSED_ADDRESS_UNIX;
    else if (pa_startswith(p, "unix:")) {
        ret_p->type = PA_PARSED_ADDRESS_UNIX;
        p += sizeof("unix:")-1;
    } else if (pa_startswith(p, "tcp:")) {
        ret_p->type = PA_PARSED_ADDRESS_TCP4;
        p += sizeof("tcp:")-1;
    } else if (pa_startswith(p, "tcp4:")) {
        ret_p->type = PA_PARSED_ADDRESS_TCP4;
        p += sizeof("tcp4:")-1;
    } else if (pa_startswith(p, "tcp6:")) {
        ret_p->type = PA_PARSED_ADDRESS_TCP6;
        p += sizeof("tcp6:")-1;
    }

    if (ret_p->type == PA_PARSED_ADDRESS_UNIX)
        ret_p->path_or_host = pa_xstrdup(p);
    else
        if (!(ret_p->path_or_host = parse_host(p, &ret_p->port)))
            return -1;

    return 0;
}
Exemplo n.º 4
0
static int proc_name_ours(pid_t pid, const char *procname) {
#ifdef __linux__
    char bn[PATH_MAX];
    FILE *f;

    pa_snprintf(bn, sizeof(bn), "/proc/%lu/stat", (unsigned long) pid);

    if (!(f = pa_fopen_cloexec(bn, "r"))) {
        pa_log_info("Failed to open %s: %s", bn, pa_cstrerror(errno));
        return -1;
    } else {
        char *expected;
        pa_bool_t good;
        char stored[64];

        if (!(fgets(stored, sizeof(stored), f))) {
            int saved_errno = feof(f) ? EINVAL : errno;
            pa_log_info("Failed to read from %s: %s", bn, feof(f) ? "EOF" : pa_cstrerror(errno));
            fclose(f);

            errno = saved_errno;
            return -1;
        }

        fclose(f);

        expected = pa_sprintf_malloc("%lu (%s)", (unsigned long) pid, procname);
        good = pa_startswith(stored, expected);
        pa_xfree(expected);

/*#if !defined(__OPTIMIZE__)*/
        if (!good) {
            /* libtool likes to rename our binary names ... */
            expected = pa_sprintf_malloc("%lu (lt-%s)", (unsigned long) pid, procname);
            good = pa_startswith(stored, expected);
            pa_xfree(expected);
        }
/*#endif*/

        return !!good;
    }
#else

    return 1;
#endif

}
static bool pcm_node_belongs_to_device(
        struct device *d,
        const char *node) {

    char *cd;
    bool b;

    cd = pa_sprintf_malloc("pcmC%sD", path_get_card_id(d->path));
    b = pa_startswith(node, cd);
    pa_xfree(cd);

    return b;
}
static const char *path_get_card_id(const char *path) {
    const char *e;

    if (!path)
        return NULL;

    if (!(e = strrchr(path, '/')))
        return NULL;

    if (!pa_startswith(e, "/card"))
        return NULL;

    return e + 5;
}
Exemplo n.º 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;
}
static pa_hook_result_t sink_input_fixate_hook_callback(pa_core *core, pa_sink_input_new_data *data, struct userdata *u) {
    const char *hpos, *vpos, *role, *id;
    double f;
    char t[PA_CVOLUME_SNPRINT_MAX];
    pa_cvolume v;

    pa_assert(data);

    if (!(role = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_ROLE)))
        return PA_HOOK_OK;

    if (!pa_streq(role, "event"))
        return PA_HOOK_OK;

    if ((id = pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID))) {

        /* The test sounds should never be positioned in space, since
         * they might be triggered themselves to configure the speakers
         * in space, which we don't want to mess up. */

        if (pa_startswith(id, "audio-channel-"))
            return PA_HOOK_OK;

        if (pa_streq(id, "audio-volume-change"))
            return PA_HOOK_OK;

        if (pa_streq(id, "audio-test-signal"))
            return PA_HOOK_OK;
    }

    if (!(hpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_HPOS)))
        hpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_HPOS);

    if (!(vpos = pa_proplist_gets(data->proplist, PA_PROP_EVENT_MOUSE_VPOS)))
        vpos = pa_proplist_gets(data->proplist, PA_PROP_WINDOW_VPOS);

    if (!hpos && !vpos)
        return PA_HOOK_OK;

    pa_cvolume_reset(&v, data->sink->sample_spec.channels);

    if (hpos) {
        if (parse_pos(hpos, &f) < 0)
            return PA_HOOK_OK;

        if (pa_channel_map_can_balance(&data->sink->channel_map)) {
            pa_log_debug("Positioning event sound '%s' horizontally at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f);
            pa_cvolume_set_balance(&v, &data->sink->channel_map, f*2.0-1.0);
        }
    }

    if (vpos) {
        if (parse_pos(vpos, &f) < 0)
            return PA_HOOK_OK;

        if (pa_channel_map_can_fade(&data->sink->channel_map)) {
            pa_log_debug("Positioning event sound '%s' vertically at %0.2f.", pa_strnull(pa_proplist_gets(data->proplist, PA_PROP_EVENT_ID)), f);
            pa_cvolume_set_fade(&v, &data->sink->channel_map, f*2.0-1.0);
        }
    }

    pa_log_debug("Final volume factor %s.", pa_cvolume_snprint(t, sizeof(t), &v));
    pa_sink_input_new_data_add_volume_factor_sink(data, u->name, &v);

    return PA_HOOK_OK;
}
static void inotify_cb(
        pa_mainloop_api*a,
        pa_io_event* e,
        int fd,
        pa_io_event_flags_t events,
        void *userdata) {

    struct {
        struct inotify_event e;
        char name[NAME_MAX];
    } buf;
    struct userdata *u = userdata;
    static int type = 0;
    bool deleted = false;
    struct device *d;
    void *state;

    for (;;) {
        ssize_t r;
        struct inotify_event *event;

        pa_zero(buf);
        if ((r = pa_read(fd, &buf, sizeof(buf), &type)) <= 0) {

            if (r < 0 && errno == EAGAIN)
                break;

            pa_log("read() from inotify failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
            goto fail;
        }

        event = &buf.e;
        while (r > 0) {
            size_t len;

            if ((size_t) r < sizeof(struct inotify_event)) {
                pa_log("read() too short.");
                goto fail;
            }

            len = sizeof(struct inotify_event) + event->len;

            if ((size_t) r < len) {
                pa_log("Payload missing.");
                goto fail;
            }

            /* From udev we get the guarantee that the control
             * device's ACL is changed last. To avoid races when ACLs
             * are changed we hence watch only the control device */
            if (((event->mask & IN_ATTRIB) && pa_startswith(event->name, "controlC")))
                PA_HASHMAP_FOREACH(d, u->devices, state)
                    if (control_node_belongs_to_device(d, event->name))
                        d->need_verify = true;

            /* ALSA doesn't really give us any guarantee on the closing
             * order, so let's simply hope */
            if (((event->mask & IN_CLOSE_WRITE) && pa_startswith(event->name, "pcmC")))
                PA_HASHMAP_FOREACH(d, u->devices, state)
                    if (pcm_node_belongs_to_device(d, event->name))
                        d->need_verify = true;

            /* /dev/snd/ might have been removed */
            if ((event->mask & (IN_DELETE_SELF|IN_MOVE_SELF)))
                deleted = true;

            event = (struct inotify_event*) ((uint8_t*) event + len);
            r -= len;
        }
    }

    PA_HASHMAP_FOREACH(d, u->devices, state)
        if (d->need_verify) {
            d->need_verify = false;
            verify_access(u, d);
        }

    if (!deleted)
        return;

fail:
    if (u->inotify_io) {
        a->io_free(u->inotify_io);
        u->inotify_io = NULL;
    }

    if (u->inotify_fd >= 0) {
        pa_close(u->inotify_fd);
        u->inotify_fd = -1;
    }
}
Exemplo n.º 10
0
static bool is_card_busy(const char *id) {
    char *card_path = NULL, *pcm_path = NULL, *sub_status = NULL;
    DIR *card_dir = NULL, *pcm_dir = NULL;
    FILE *status_file = NULL;
    size_t len;
    struct dirent *space = NULL, *de;
    bool busy = false;
    int r;

    pa_assert(id);

    /* This simply uses /proc/asound/card.../pcm.../sub.../status to
     * check whether there is still a process using this audio device. */

    card_path = pa_sprintf_malloc("/proc/asound/card%s", id);

    if (!(card_dir = opendir(card_path))) {
        pa_log_warn("Failed to open %s: %s", card_path, pa_cstrerror(errno));
        goto fail;
    }

    len = offsetof(struct dirent, d_name) + fpathconf(dirfd(card_dir), _PC_NAME_MAX) + 1;
    space = pa_xmalloc(len);

    for (;;) {
        de = NULL;

        if ((r = readdir_r(card_dir, space, &de)) != 0) {
            pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r));
            goto fail;
        }

        if (!de)
            break;

        if (!pa_startswith(de->d_name, "pcm"))
            continue;

        if (pcm_is_modem(id, de->d_name + 3))
            continue;

        pa_xfree(pcm_path);
        pcm_path = pa_sprintf_malloc("%s/%s", card_path, de->d_name);

        if (pcm_dir)
            closedir(pcm_dir);

        if (!(pcm_dir = opendir(pcm_path))) {
            pa_log_warn("Failed to open %s: %s", pcm_path, pa_cstrerror(errno));
            continue;
        }

        for (;;) {
            char line[32];

            if ((r = readdir_r(pcm_dir, space, &de)) != 0) {
                pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r));
                goto fail;
            }

            if (!de)
                break;

            if (!pa_startswith(de->d_name, "sub"))
                continue;

            pa_xfree(sub_status);
            sub_status = pa_sprintf_malloc("%s/%s/status", pcm_path, de->d_name);

            if (status_file)
                fclose(status_file);

            if (!(status_file = pa_fopen_cloexec(sub_status, "r"))) {
                pa_log_warn("Failed to open %s: %s", sub_status, pa_cstrerror(errno));
                continue;
            }

            if (!(fgets(line, sizeof(line)-1, status_file))) {
                pa_log_warn("Failed to read from %s: %s", sub_status, pa_cstrerror(errno));
                continue;
            }

            if (!pa_streq(line, "closed\n")) {
                busy = true;
                break;
            }
        }
    }

fail:

    pa_xfree(card_path);
    pa_xfree(pcm_path);
    pa_xfree(sub_status);
    pa_xfree(space);

    if (card_dir)
        closedir(card_dir);

    if (pcm_dir)
        closedir(pcm_dir);

    if (status_file)
        fclose(status_file);

    return busy;
}