Esempio n. 1
0
void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn) {
    FILE *f;
    void *p;

    pa_assert(c);
    pa_assert(fn);

    /* Only for debugging purposes */

    f = pa_fopen_cloexec(fn, "a");

    if (!f) {
        pa_log_warn("Failed to open '%s': %s", fn, pa_cstrerror(errno));
        return;
    }

    p = pa_memblock_acquire(c->memblock);

    if (fwrite((uint8_t*) p + c->index, 1, c->length, f) != c->length)
        pa_log_warn("Failed to write to '%s': %s", fn, pa_cstrerror(errno));

    pa_memblock_release(c->memblock);

    fclose(f);
}
Esempio n. 2
0
/* Read the PID data from the file descriptor fd, and return it. If no
 * pid could be read, return 0, on failure (pid_t) -1 */
static pid_t read_pid(const char *fn, int fd) {
    ssize_t r;
    char t[20], *e;
    uint32_t pid;

    pa_assert(fn);
    pa_assert(fd >= 0);

    if ((r = pa_loop_read(fd, t, sizeof(t)-1, NULL)) < 0) {
        pa_log_warn("Failed to read PID file '%s': %s", fn, pa_cstrerror(errno));
        return (pid_t) -1;
    }

    if (r == 0)
        return (pid_t) 0;

    t[r] = 0;
    if ((e = strchr(t, '\n')))
        *e = 0;

    if (pa_atou(t, &pid) < 0) {
        pa_log_warn("Failed to parse PID file '%s'", fn);
        errno = EINVAL;
        return (pid_t) -1;
    }

    return (pid_t) pid;
}
Esempio n. 3
0
/* Raise the priority of the current process as much as possible that
 * is <= the specified nice level..*/
int pa_raise_priority(int nice_level) {

#ifdef HAVE_SYS_RESOURCE_H
    if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) {
        int n;

        for (n = nice_level+1; n < 0; n++) {

            if (setpriority(PRIO_PROCESS, 0, n) == 0) {
                pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
                return 0;
            }
        }

        pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
        return -1;
    }

    pa_log_info("Successfully gained nice level %i.", nice_level);
#endif

#ifdef OS_IS_WIN32
    if (nice_level < 0) {
        if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
            pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
            return .-1;
        } else
Esempio n. 4
0
static pa_dbus_connection *register_dbus(pa_core *c) {
    DBusError error;
    pa_dbus_connection *conn;

    dbus_error_init(&error);

    if (!(conn = pa_dbus_bus_get(c, pa_in_system_mode() ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
        pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message);
        goto fail;
    }

    if (dbus_bus_request_name(pa_dbus_connection_get(conn), "org.pulseaudio.Server", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
        pa_log_debug("Got org.pulseaudio.Server!");
        return conn;
    }

    if (dbus_error_is_set(&error))
        pa_log_warn("Failed to acquire org.pulseaudio.Server: %s: %s", error.name, error.message);
    else
        pa_log_warn("D-Bus name org.pulseaudio.Server already taken. Weird shit!");

    /* PA cannot be started twice by the same user and hence we can
     * ignore mostly the case that org.pulseaudio.Server is already
     * taken. */

fail:

    if (conn)
        pa_dbus_connection_unref(conn);

    dbus_error_free(&error);
    return NULL;
}
Esempio n. 5
0
/* Load an authorization cookie from file fn and store it in data. If
 * the cookie file doesn't exist, create it */
static int load(const char *fn, void *data, size_t length) {
    int fd = -1;
    int writable = 1;
    int unlock = 0, ret = -1;
    ssize_t r;

    pa_assert(fn);
    pa_assert(data);
    pa_assert(length > 0);

    if ((fd = pa_open_cloexec(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {

        if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
            pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
            goto finish;
        } else
            writable = 0;
    }

    unlock = pa_lock_fd(fd, 1) >= 0;

    if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
        pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
        goto finish;
    }

    if ((size_t) r != length) {
        pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);

        if (!writable) {
            pa_log_warn("Unable to write cookie to read-only file");
            goto finish;
        }

        if (generate(fd, data, length) < 0)
            goto finish;
    }

    ret = 0;

finish:

    if (fd >= 0) {

        if (unlock)
            pa_lock_fd(fd, 0);

        if (pa_close(fd) < 0) {
            pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
            ret = -1;
        }
    }

    return ret;
}
Esempio n. 6
0
static int open_pid_file(const char *fn, int mode) {
    int fd;

    pa_assert(fn);

    for (;;) {
        struct stat st;

        if ((fd = pa_open_cloexec(fn, mode
#ifdef O_NOFOLLOW
                       |O_NOFOLLOW
#endif
                       , S_IRUSR|S_IWUSR
             )) < 0) {
            if (mode != O_RDONLY || errno != ENOENT)
                pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
            goto fail;
        }

        /* Try to lock the file. If that fails, go without */
        if (pa_lock_fd(fd, 1) < 0)
            goto fail;

        if (fstat(fd, &st) < 0) {
            pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno));
            goto fail;
        }

        /* Does the file still exist in the file system? When yes, we're done, otherwise restart */
        if (st.st_nlink >= 1)
            break;

        if (pa_lock_fd(fd, 0) < 0)
            goto fail;

        if (pa_close(fd) < 0) {
            pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
            fd = -1;
            goto fail;
        }
    }

    return fd;

fail:

    if (fd >= 0) {
        int saved_errno = errno;
        pa_lock_fd(fd, 0);
        pa_close(fd);
        errno = saved_errno;
    }

    return -1;
}
Esempio n. 7
0
static struct entry* read_entry(struct userdata *u, const char *name) {
    pa_datum key, data;
    struct entry *e;

    pa_assert(u);
    pa_assert(name);

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

    pa_zero(data);

    if (!pa_database_get(u->database, &key, &data))
        goto fail;

    if (data.size != sizeof(struct entry)) {
        pa_log_debug("Database contains entry for device %s of wrong size %lu != %lu. Probably due to upgrade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry));
        goto fail;
    }

    e = (struct entry*) data.data;

    if (e->version != ENTRY_VERSION) {
        pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name);
        goto fail;
    }

    if (!memchr(e->port, 0, sizeof(e->port))) {
        pa_log_warn("Database contains entry for device %s with missing NUL byte in port name", name);
        goto fail;
    }

    if (e->volume_valid && !pa_channel_map_valid(&e->channel_map)) {
        pa_log_warn("Invalid channel map stored in database for device %s", name);
        goto fail;
    }

    if (e->volume_valid && (!pa_cvolume_valid(&e->volume) || !pa_cvolume_compatible_with_channel_map(&e->volume, &e->channel_map))) {
        pa_log_warn("Volume and channel map don't match in database entry for device %s", name);
        goto fail;
    }

    return e;

fail:

    pa_datum_free(&data);
    return NULL;
}
Esempio n. 8
0
static int sco_acquire_cb(pa_bluetooth_transport *t, bool optional, size_t *imtu, size_t *omtu) {
    int sock;
    socklen_t len;

    if (optional)
        sock = sco_do_accept(t);
    else
        sock = sco_do_connect(t);

    if (sock < 0)
        goto fail;

    if (imtu) *imtu = 48;
    if (omtu) *omtu = 48;

    if (t->device->autodetect_mtu) {
        struct sco_options sco_opt;

        len = sizeof(sco_opt);
        memset(&sco_opt, 0, len);

        if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0)
            pa_log_warn("getsockopt(SCO_OPTIONS) failed, loading defaults");
        else {
            if (imtu) *imtu = sco_opt.mtu;
            if (omtu) *omtu = sco_opt.mtu;
        }
    }

    return sock;

fail:
    return -1;
}
Esempio n. 9
0
static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
#ifdef HAVE_SYS_RESOURCE_H
    struct pa_rlimit *r = data;

    pa_assert(filename);
    pa_assert(lvalue);
    pa_assert(rvalue);
    pa_assert(r);

    if (rvalue[strspn(rvalue, "\t ")] == 0) {
        /* Empty string */
        r->is_set = 0;
        r->value = 0;
    } else {
        int32_t k;
        if (pa_atoi(rvalue, &k) < 0) {
            pa_log(_("[%s:%u] Invalid rlimit '%s'."), filename, line, rvalue);
            return -1;
        }
        r->is_set = k >= 0;
        r->value = k >= 0 ? (rlim_t) k : 0;
    }
#else
    pa_log_warn(_("[%s:%u] rlimit not supported on this platform."), filename, line);
#endif

    return 0;
}
Esempio n. 10
0
static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) {
    DBusError error;
    pa_dbus_connection *conn;

    dbus_error_init(&error);

    if (!(conn = pa_dbus_bus_get(c, bus, &error)) || dbus_error_is_set(&error)) {
        pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message);
        goto fail;
    }

    if (dbus_bus_request_name(pa_dbus_connection_get(conn), name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
        pa_log_debug("Got %s!", name);
        return conn;
    }

    if (dbus_error_is_set(&error))
        pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message);
    else
        pa_log_error("D-Bus name %s already taken.", name);

    /* PA cannot be started twice by the same user and hence we can
     * ignore mostly the case that a name is already taken. */

fail:
    if (conn)
        pa_dbus_connection_unref(conn);

    dbus_error_free(&error);
    return NULL;
}
Esempio n. 11
0
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 event;
        char name[NAME_MAX+1];
    } buf;

    pa_inotify *i = userdata;
    int pid_fd;

    pa_assert(i);

    if (pa_read(fd, &buf, sizeof(buf), NULL) < (int) sizeof(buf.event))
        pa_log_warn("inotify did not read a full event.");
    else
        pa_log_debug("inotify callback, event mask: 0x%x", (int) buf.event.mask);

    pid_fd = pa_open_cloexec(i->filename, O_RDONLY
#ifdef O_NOFOLLOW
                       |O_NOFOLLOW
#endif
                       , S_IRUSR);

    if (pid_fd < 0) {
        if (i->callback)
            i->callback(i->callback_data);
    } else
        pa_close(pid_fd);
}
Esempio n. 12
0
static void load_null_sink_if_needed(pa_core *c, pa_sink *sink, struct userdata* u) {
    pa_sink *target;
    uint32_t idx;
    char *t;
    pa_module *m;

    pa_assert(c);
    pa_assert(u);
    pa_assert(u->null_module == PA_INVALID_INDEX);

    /* Loop through all sinks and check to see if we have *any*
     * sinks. Ignore the sink passed in (if it's not null) */
    for (target = pa_idxset_first(c->sinks, &idx); target; target = pa_idxset_next(c->sinks, &idx))
        if (!sink || target != sink)
            break;

    if (target)
        return;

    pa_log_debug("Autoloading null-sink as no other sinks detected.");

    u->ignore = TRUE;

    t = pa_sprintf_malloc("sink_name=%s sink_properties='device.description=\"%s\"'", u->sink_name,
                          _("Dummy Output"));
    m = pa_module_load(c, "module-null-sink", t);
    u->null_module = m ? m->index : PA_INVALID_INDEX;
    pa_xfree(t);

    u->ignore = FALSE;

    if (!m)
        pa_log_warn("Unable to load module-null-sink");
}
Esempio n. 13
0
void pa_mempool_free(pa_mempool *p) {
    pa_assert(p);

    pa_mutex_lock(p->mutex);

    while (p->imports)
        pa_memimport_free(p->imports);

    while (p->exports)
        pa_memexport_free(p->exports);

    pa_mutex_unlock(p->mutex);

    pa_flist_free(p->free_slots, NULL);

    if (pa_atomic_load(&p->stat.n_allocated) > 0) {
/*         raise(SIGTRAP);  */
        pa_log_warn("Memory pool destroyed but not all memory blocks freed! %u remain.", pa_atomic_load(&p->stat.n_allocated));
    }

    pa_shm_free(&p->memory);

    pa_mutex_free(p->mutex);
    pa_semaphore_free(p->semaphore);

    pa_xfree(p);
}
Esempio n. 14
0
pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c) {
    pa_dbusobj_server_lookup *sl;
    DBusError error;

    dbus_error_init(&error);

    sl = pa_xnew(pa_dbusobj_server_lookup, 1);
    sl->core = c;
    sl->path_registered = false;

    if (!(sl->conn = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
        pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message);
        goto fail;
    }

    if (!dbus_connection_register_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH, &vtable, sl)) {
        pa_log("dbus_connection_register_object_path() failed for " OBJECT_PATH ".");
        goto fail;
    }

    sl->path_registered = true;

    return sl;

fail:
    dbus_error_free(&error);

    pa_dbusobj_server_lookup_free(sl);

    return NULL;
}
Esempio n. 15
0
static bool parse_device_list(const char *str, audio_devices_t *dst) {
    char *dev;
    const char *state = NULL;

    pa_assert(str);
    pa_assert(dst);

    *dst = 0;

    while ((dev = pa_split(str, "|", &state))) {
        audio_devices_t d;

        if (!pa_string_convert_input_device_str_to_num(dev, &d)) {
            pa_log_warn("Unknown device %s", dev);
            pa_xfree(dev);
            return false;
        }

        *dst |= d;

        pa_xfree(dev);
    }

    return true;
}
static void jack_error_func(const char*t) {
    char *s;

    s = pa_xstrndup(t, strcspn(t, "\n\r"));
    pa_log_warn("JACK error >%s<", s);
    pa_xfree(s);
}
int pa__init(pa_module*m) {
    pa_modargs *ma = NULL;
    int ret = -1;
    uint32_t pid = 0;

    pa_assert(m);

    if (!(ma = pa_modargs_new(m->argument, valid_modargs)) ||
        pa_modargs_get_value_u32(ma, "pid", &pid) < 0 ||
        !pid) {
        pa_log("Failed to parse module arguments");
        goto finish;
    }

    if (kill((pid_t) pid, SIGUSR1) < 0)
        pa_log_warn("kill(%u) failed: %s", pid, pa_cstrerror(errno));

    pa_module_unload_request(m, true);

    ret = 0;

finish:
    if (ma)
        pa_modargs_free(ma);

    return ret;
}
Esempio n. 18
0
void pa_asyncq_post(pa_asyncq*l, void *p) {
    struct localq *q;

    pa_assert(l);
    pa_assert(p);

    if (flush_postq(l, FALSE))
        if (pa_asyncq_push(l, p, FALSE) >= 0)
            return;

    /* OK, we couldn't push anything in the queue. So let's queue it
     * locally and push it later */

    if (pa_log_ratelimit())
        pa_log_warn("q overrun, queuing locally");

    if (!(q = pa_flist_pop(PA_STATIC_FLIST_GET(localq))))
        q = pa_xnew(struct localq, 1);

    q->data = p;
    PA_LLIST_PREPEND(struct localq, l->localq, q);

    if (!l->last_localq)
        l->last_localq = q;

    return;
}
static struct pa_policy_group* get_group(struct userdata *u, const char *group_name, pa_proplist *sinp_proplist, uint32_t *flags_ret)
{
    struct pa_policy_group *group = NULL;
    const void *flags;
    size_t len_flags = 0;

    pa_assert(u);
    pa_assert(sinp_proplist);

    /* If group name is provided use that, otherwise check sink input proplist. */
    if (!group_name)
        /* Just grab the group name from the proplist to avoid classifying multiple
         * times (and to avoid classifying incorrectly if properties are
         * overwritten when handling PA_CORE_HOOK_SINK_INPUT_NEW).*/
        group_name = pa_proplist_gets(sinp_proplist, PA_PROP_POLICY_GROUP);

    if (group_name && (group = pa_policy_group_find(u, group_name)) != NULL) {
        /* Only update flags if flags_ret is non null */
        if (flags_ret) {
            if (pa_proplist_get(sinp_proplist, PA_PROP_POLICY_STREAM_FLAGS, &flags, &len_flags) < 0 ||
                len_flags != sizeof(uint32_t)) {

                pa_log_warn("No stream flags in proplist or malformed flags.");
                *flags_ret = 0;
            } else
                *flags_ret = *(uint32_t *)flags;
        }
    }

    return group;
}
int pa__init(pa_module*m) {
    pa_modargs *ma = NULL;
    int ret = -1;
    int32_t fd = -1;
    char x = 1;

    pa_assert(m);

    if (!(ma = pa_modargs_new(m->argument, valid_modargs)) ||
            pa_modargs_get_value_s32(ma, "fd", &fd) < 0 ||
            fd < 0) {

        pa_log("Failed to parse module arguments");
        goto finish;
    }

    if (pa_loop_write(fd, &x, sizeof(x), NULL) != sizeof(x))
        pa_log_warn("write(%u, 1, 1) failed: %s", fd, pa_cstrerror(errno));

    pa_assert_se(pa_close(fd) == 0);

    pa_module_unload_request(m, true);

    ret = 0;

finish:
    if (ma)
        pa_modargs_free(ma);

    return ret;
}
Esempio n. 21
0
void pa_rtclock_hrtimer_enable(void) {

#ifdef PR_SET_TIMERSLACK
    int slack_ns;

    if ((slack_ns = prctl(PR_GET_TIMERSLACK, 0, 0, 0, 0)) < 0) {
        pa_log_info("PR_GET_TIMERSLACK/PR_SET_TIMERSLACK not supported.");
        return;
    }

    pa_log_debug("Timer slack is set to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));

    if (slack_ns > TIMER_SLACK_NS) {
        slack_ns = TIMER_SLACK_NS;

        pa_log_debug("Setting timer slack to %i us.", (int) (slack_ns/PA_NSEC_PER_USEC));

        if (prctl(PR_SET_TIMERSLACK, slack_ns, 0, 0, 0) < 0) {
            pa_log_warn("PR_SET_TIMERSLACK failed: %s", pa_cstrerror(errno));
            return;
        }
    }

#elif defined(OS_IS_WIN32)
    LARGE_INTEGER freq;

    pa_assert_se(QueryPerformanceFrequency(&freq));
    counter_freq = freq.QuadPart;

#endif
}
Esempio n. 22
0
/* pa_io_event_cb_t IO event handler */
static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
    unsigned int flags = 0;
    DBusWatch *watch = userdata;

#if HAVE_DBUS_WATCH_GET_UNIX_FD
    pa_assert(fd == dbus_watch_get_unix_fd(watch));
#else
    pa_assert(fd == dbus_watch_get_fd(watch));
#endif

    if (!dbus_watch_get_enabled(watch)) {
        pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
        return;
    }

    if (events & PA_IO_EVENT_INPUT)
        flags |= DBUS_WATCH_READABLE;
    if (events & PA_IO_EVENT_OUTPUT)
        flags |= DBUS_WATCH_WRITABLE;
    if (events & PA_IO_EVENT_HANGUP)
        flags |= DBUS_WATCH_HANGUP;
    if (events & PA_IO_EVENT_ERROR)
        flags |= DBUS_WATCH_ERROR;

    dbus_watch_handle(watch, flags);
}
static void load(struct userdata *u) {
    FILE *f;

    /* We never overwrite manually configured settings */

    if (u->core->configured_default_sink)
        pa_log_info("Manually configured default sink, not overwriting.");
    else if ((f = pa_fopen_cloexec(u->sink_filename, "r"))) {
        char ln[256] = "";

        if (fgets(ln, sizeof(ln)-1, f))
            pa_strip_nl(ln);
        fclose(f);

        if (!ln[0])
            pa_log_info("No previous default sink setting, ignoring.");
        else if (!pa_namereg_is_valid_name(ln))
            pa_log_warn("Invalid sink name: %s", ln);
        else {
            pa_log_info("Restoring default sink '%s'.", ln);
            pa_core_set_configured_default_sink(u->core, ln);
        }

    } else if (errno != ENOENT)
        pa_log("Failed to load default sink: %s", pa_cstrerror(errno));

    if (u->core->configured_default_source)
        pa_log_info("Manually configured default source, not overwriting.");
    else if ((f = pa_fopen_cloexec(u->source_filename, "r"))) {
        char ln[256] = "";

        if (fgets(ln, sizeof(ln)-1, f))
            pa_strip_nl(ln);
        fclose(f);

        if (!ln[0])
            pa_log_info("No previous default source setting, ignoring.");
        else if (!pa_namereg_is_valid_name(ln))
            pa_log_warn("Invalid source name: %s", ln);
        else {
            pa_log_info("Restoring default source '%s'.", ln);
            pa_core_set_configured_default_source(u->core, ln);
        }

    } else if (errno != ENOENT)
        pa_log("Failed to load default source: %s", pa_cstrerror(errno));
}
/* Called from main context */
static void adjust_rates(struct userdata *u) {
    size_t buffer, fs;
    uint32_t old_rate, base_rate, new_rate;
    pa_usec_t buffer_latency;

    pa_assert(u);
    pa_assert_ctl_context();

    pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);
    pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL);

    buffer =
        u->latency_snapshot.sink_input_buffer +
        u->latency_snapshot.source_output_buffer;

    if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter)
        buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter);
    else
        buffer += PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter));

    buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec);

    pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms",
                (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
                (double) buffer_latency / PA_USEC_PER_MSEC,
                (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
                ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC);

    pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes",
                u->latency_snapshot.max_request*2,
                u->latency_snapshot.min_memblockq_length);

    fs = pa_frame_size(&u->sink_input->sample_spec);
    old_rate = u->sink_input->sample_spec.rate;
    base_rate = u->source_output->sample_spec.rate;

    if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2)
        new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;
    else
        new_rate = base_rate + (((u->latency_snapshot.min_memblockq_length - u->latency_snapshot.max_request*2) / fs) *PA_USEC_PER_SEC)/u->adjust_time;

    if (new_rate < (uint32_t) (base_rate*0.8) || new_rate > (uint32_t) (base_rate*1.25)) {
        pa_log_warn("Sample rates too different, not adjusting (%u vs. %u).", base_rate, new_rate);
        new_rate = base_rate;
    } else {
        if (base_rate < new_rate + 20 && new_rate < base_rate + 20)
          new_rate = base_rate;
        /* Do the adjustment in small steps; 2‰ can be considered inaudible */
        if (new_rate < (uint32_t) (old_rate*0.998) || new_rate > (uint32_t) (old_rate*1.002)) {
            pa_log_info("New rate of %u Hz not within 2‰ of %u Hz, forcing smaller adjustment", new_rate, old_rate);
            new_rate = PA_CLAMP(new_rate, (uint32_t) (old_rate*0.998), (uint32_t) (old_rate*1.002));
        }
    }

    pa_sink_input_set_rate(u->sink_input, new_rate);
    pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate);

    pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
}
Esempio n. 25
0
/** Creates a directory securely */
int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
    struct stat st;
    int r;

    pa_assert(dir);

#ifdef OS_IS_WIN32
    r = mkdir(dir);
#else
    {
    mode_t u;
    u = umask(~m);
    r = mkdir(dir, m);
    umask(u);
    }
#endif

    if (r < 0 && errno != EEXIST)
        return -1;

#ifdef HAVE_CHOWN
    if (uid == (uid_t)-1)
        uid = getuid();
    if (gid == (gid_t)-1)
        gid = getgid();
    (void) chown(dir, uid, gid);
#endif

#ifdef HAVE_CHMOD
    chmod(dir, m);
#endif

#ifdef HAVE_LSTAT
    if (lstat(dir, &st) < 0)
#else
    if (stat(dir, &st) < 0)
#endif
        goto fail;

#ifndef OS_IS_WIN32
    if (!S_ISDIR(st.st_mode) ||
        (st.st_uid != uid) ||
        (st.st_gid != gid) ||
        ((st.st_mode & 0777) != m)) {
        errno = EACCES;
        goto fail;
    }
#else
    pa_log_warn("secure directory creation not supported on Win32.");
#endif

    return 0;

fail:
    rmdir(dir);
    return -1;
}
Esempio n. 26
0
/* Store the specified cookie in the specified cookie file */
int pa_authkey_save(const char *fn, const void *data, size_t length) {
    int fd = -1;
    int unlock = 0, ret = -1;
    ssize_t r;
    char *p;

    pa_assert(fn);
    pa_assert(data);
    pa_assert(length > 0);

    if (!(p = normalize_path(fn)))
        return -2;

    if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
        pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
        goto finish;
    }

    unlock = pa_lock_fd(fd, 1) >= 0;

    if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
        pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
        goto finish;
    }

    ret = 0;

finish:

    if (fd >= 0) {

        if (unlock)
            pa_lock_fd(fd, 0);

        if (pa_close(fd) < 0) {
            pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
            ret = -1;
        }
    }

    pa_xfree(p);

    return ret;
}
Esempio n. 27
0
static int do_write(struct userdata *u) {
    ssize_t r;
    pa_assert(u);

    if (!pa_iochannel_is_writable(u->io))
        return 0;

    if (u->write_data) {
        pa_assert(u->write_index < u->write_length);

        if ((r = pa_iochannel_write(u->io, (uint8_t*) u->write_data + u->write_index, u->write_length - u->write_index)) <= 0) {
            pa_log("write() failed: %s", pa_cstrerror(errno));
            return -1;
        }

        u->write_index += (size_t) r;
        pa_assert(u->write_index <= u->write_length);

        if (u->write_index == u->write_length) {
            pa_xfree(u->write_data);
            u->write_data = NULL;
            u->write_index = u->write_length = 0;
        }
    }

    if (!u->write_data && u->state == STATE_PREPARE) {
        int so_sndbuf = 0;
        socklen_t sl = sizeof(int);

        /* OK, we're done with sending all control data we need to, so
         * let's hand the socket over to the IO thread now */

        pa_assert(u->fd < 0);
        u->fd = pa_iochannel_get_send_fd(u->io);

        pa_iochannel_set_noclose(u->io, TRUE);
        pa_iochannel_free(u->io);
        u->io = NULL;

        pa_make_tcp_socket_low_delay(u->fd);

        if (getsockopt(u->fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, &sl) < 0)
            pa_log_warn("getsockopt(SO_SNDBUF) failed: %s", pa_cstrerror(errno));
        else {
            pa_log_debug("SO_SNDBUF is %zu.", (size_t) so_sndbuf);
            pa_sink_set_max_request(u->sink, PA_MAX((size_t) so_sndbuf, u->block_size));
        }

        pa_log_debug("Connection authenticated, handing fd to IO thread...");

        pa_asyncmsgq_post(u->thread_mq.inq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_PASS_SOCKET, NULL, 0, NULL, NULL);
        u->state = STATE_RUNNING;
    }

    return 0;
}
Esempio n. 28
0
void pa_client_kill(pa_client *c) {
    pa_assert(c);

    if (!c->kill) {
        pa_log_warn("kill() operation not implemented for client %u", c->index);
        return;
    }

    c->kill(c);
}
Esempio n. 29
0
static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) {
    pa_socket_server *s = userdata;
    pa_iochannel *io;
    int nfd;

    pa_assert(s);
    pa_assert(PA_REFCNT_VALUE(s) >= 1);
    pa_assert(s->mainloop == mainloop);
    pa_assert(s->io_event == e);
    pa_assert(e);
    pa_assert(fd >= 0);
    pa_assert(fd == s->fd);

    pa_socket_server_ref(s);

    if ((nfd = pa_accept_cloexec(fd, NULL, NULL)) < 0) {
        pa_log("accept(): %s", pa_cstrerror(errno));
        goto finish;
    }

    if (!s->on_connection) {
        pa_close(nfd);
        goto finish;
    }

#ifdef HAVE_LIBWRAP

    if (s->tcpwrap_service) {
        struct request_info req;

        request_init(&req, RQ_DAEMON, s->tcpwrap_service, RQ_FILE, nfd, NULL);
        fromhost(&req);
        if (!hosts_access(&req)) {
            pa_log_warn("TCP connection refused by tcpwrap.");
            pa_close(nfd);
            goto finish;
        }

        pa_log_info("TCP connection accepted by tcpwrap.");
    }
#endif

    /* There should be a check for socket type here */
    if (s->type == SOCKET_SERVER_IPV4)
        pa_make_tcp_socket_low_delay(fd);
    else
        pa_make_socket_low_delay(fd);

    pa_assert_se(io = pa_iochannel_new(s->mainloop, nfd, nfd));
    s->on_connection(s, io, s->userdata);

finish:
    pa_socket_server_unref(s);
}
Esempio n. 30
0
int mv_parse_steps(struct mv_userdata *u, const char *route, const char *step_string_call, const char *step_string_media) {
    int count1 = 0;
    int count2 = 0;
    struct mv_volume_steps_set *set;
    struct mv_volume_steps call_steps;
    struct mv_volume_steps media_steps;

    pa_assert(u);
    pa_assert(u->steps);
    pa_assert(route);

    if (!step_string_call || !step_string_media) {
        return 0;
    }

    count1 = mv_parse_single_steps(&call_steps, step_string_call);
    if (count1 < 1) {
        pa_log_warn("failed to parse call steps; %s", step_string_call);
        return -1;
    }
    mv_normalize_steps(&call_steps);

    count2 = mv_parse_single_steps(&media_steps, step_string_media);
    if (count2 < 1) {
        pa_log_warn("failed to parse media steps; %s", step_string_media);
        return -1;
    }
    mv_normalize_steps(&media_steps);

    set = pa_xnew0(struct mv_volume_steps_set, 1);
    set->route = pa_xstrdup(route);
    set->call = call_steps;
    set->media = media_steps;
    pa_log_debug("adding %d call and %d media steps with route %s",
                 set->call.n_steps,
                 set->media.n_steps,
                 set->route);
    pa_hashmap_put(u->steps, set->route, set);

    return count1 + count2;
}