Beispiel #1
0
static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
    struct userdata *u =  userdata;
    pa_sink_input *si = NULL;
    pa_source_output *so = NULL;
    struct rule *r;
    char *name;

    pa_assert(c);
    pa_assert(u);

    if (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
        t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
        t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_NEW) &&
        t != (PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE))
        return;

    if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
        if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx)))
            return;

        if (!si->client || !(name = client_name(si->client)))
            return;
    } else {
        pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT);

        if (!(so = pa_idxset_get_by_index(c->source_outputs, idx)))
            return;

        if (!so->client || !(name = client_name(so->client)))
            return;
    }

    if ((r = pa_hashmap_get(u->hashmap, name))) {
        pa_xfree(name);

        if (si) {

            if (!r->volume_is_set || !pa_cvolume_equal(pa_sink_input_get_volume(si), &r->volume)) {
                pa_log_info("Saving volume for <%s>", r->name);
                r->volume = *pa_sink_input_get_volume(si);
                r->volume_is_set = TRUE;
                u->modified = TRUE;
            }

            if (!r->sink || strcmp(si->sink->name, r->sink) != 0) {
                pa_log_info("Saving sink for <%s>", r->name);
                pa_xfree(r->sink);
                r->sink = pa_xstrdup(si->sink->name);
                u->modified = TRUE;
            }
        } else {
            pa_assert(so);

            if (!r->source || strcmp(so->source->name, r->source) != 0) {
                pa_log_info("Saving source for <%s>", r->name);
                pa_xfree(r->source);
                r->source = pa_xstrdup(so->source->name);
                u->modified = TRUE;
            }
        }

    } else {
        pa_log_info("Creating new entry for <%s>", name);

        r = pa_xnew(struct rule, 1);
        r->name = name;

        if (si) {
            r->volume = *pa_sink_input_get_volume(si);
            r->volume_is_set = TRUE;
            r->sink = pa_xstrdup(si->sink->name);
            r->source = NULL;
        } else {
            pa_assert(so);
            r->volume_is_set = FALSE;
            r->sink = NULL;
            r->source = pa_xstrdup(so->source->name);
        }

        pa_hashmap_put(u->hashmap, r->name, r);
        u->modified = TRUE;
    }

    if (u->modified && !u->save_time_event) {
        struct timeval tv;
        pa_gettimeofday(&tv);
        tv.tv_sec += SAVE_INTERVAL;
        u->save_time_event = u->core->mainloop->time_new(u->core->mainloop, &tv, save_time_callback, u);
    }
}
Beispiel #2
0
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_modargs *ma = NULL;
    const char *dst_addr;
    const char *src_addr;
    uint32_t port = DEFAULT_PORT, mtu;
    uint32_t ttl = DEFAULT_TTL;
    sa_family_t af;
    int fd = -1, sap_fd = -1;
    pa_source *s;
    pa_sample_spec ss;
    pa_channel_map cm;
    struct sockaddr_in dst_sa4, dst_sap_sa4, src_sa4, src_sap_sa4;
#ifdef HAVE_IPV6
    struct sockaddr_in6 dst_sa6, dst_sap_sa6, src_sa6, src_sap_sa6;
#endif
    struct sockaddr_storage sa_dst;
    pa_source_output *o = NULL;
    uint8_t payload;
    char *p;
    int r, j;
    socklen_t k;
    char hn[128], *n;
    bool loop = false;
    enum inhibit_auto_suspend inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ONLY_WITH_NON_MONITOR_SOURCES;
    const char *inhibit_auto_suspend_str;
    pa_source_output_new_data data;

    pa_assert(m);

    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
        pa_log("Failed to parse module arguments");
        goto fail;
    }

    if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) {
        pa_log("Source does not exist.");
        goto fail;
    }

    if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) {
        pa_log("Failed to parse \"loop\" parameter.");
        goto fail;
    }

    if ((inhibit_auto_suspend_str = pa_modargs_get_value(ma, "inhibit_auto_suspend", NULL))) {
        if (pa_streq(inhibit_auto_suspend_str, "always"))
            inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ALWAYS;
        else if (pa_streq(inhibit_auto_suspend_str, "never"))
            inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_NEVER;
        else if (pa_streq(inhibit_auto_suspend_str, "only_with_non_monitor_sources"))
            inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ONLY_WITH_NON_MONITOR_SOURCES;
        else {
            pa_log("Failed to parse the \"inhibit_auto_suspend\" parameter.");
            goto fail;
        }
    }

    ss = s->sample_spec;
    pa_rtp_sample_spec_fixup(&ss);
    cm = s->channel_map;
    if (pa_modargs_get_sample_spec(ma, &ss) < 0) {
        pa_log("Failed to parse sample specification");
        goto fail;
    }

    if (!pa_rtp_sample_spec_valid(&ss)) {
        pa_log("Specified sample type not compatible with RTP");
        goto fail;
    }

    if (ss.channels != cm.channels)
        pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_AIFF);

    payload = pa_rtp_payload_from_sample_spec(&ss);

    mtu = (uint32_t) pa_frame_align(DEFAULT_MTU, &ss);

    if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) {
        pa_log("Invalid MTU.");
        goto fail;
    }

    port = DEFAULT_PORT + ((uint32_t) (rand() % 512) << 1);
    if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) {
        pa_log("port= expects a numerical argument between 1 and 65535.");
        goto fail;
    }

    if (port & 1)
        pa_log_warn("Port number not even as suggested in RFC3550!");

    if (pa_modargs_get_value_u32(ma, "ttl", &ttl) < 0 || ttl < 1 || ttl > 0xFF) {
        pa_log("ttl= expects a numerical argument between 1 and 255.");
        goto fail;
    }

    src_addr = pa_modargs_get_value(ma, "source_ip", DEFAULT_SOURCE_IP);

    if (inet_pton(AF_INET, src_addr, &src_sa4.sin_addr) > 0) {
        src_sa4.sin_family = af = AF_INET;
        src_sa4.sin_port = htons(0);
        memset(&src_sa4.sin_zero, 0, sizeof(src_sa4.sin_zero));
        src_sap_sa4 = src_sa4;
#ifdef HAVE_IPV6
    } else if (inet_pton(AF_INET6, src_addr, &src_sa6.sin6_addr) > 0) {
        src_sa6.sin6_family = af = AF_INET6;
        src_sa6.sin6_port = htons(0);
        src_sa6.sin6_flowinfo = 0;
        src_sa6.sin6_scope_id = 0;
        src_sap_sa6 = src_sa6;
#endif
    } else {
        pa_log("Invalid source address '%s'", src_addr);
        goto fail;
    }

    dst_addr = pa_modargs_get_value(ma, "destination", NULL);
    if (dst_addr == NULL)
        dst_addr = pa_modargs_get_value(ma, "destination_ip", DEFAULT_DESTINATION_IP);

    if (inet_pton(AF_INET, dst_addr, &dst_sa4.sin_addr) > 0) {
        dst_sa4.sin_family = af = AF_INET;
        dst_sa4.sin_port = htons((uint16_t) port);
        memset(&dst_sa4.sin_zero, 0, sizeof(dst_sa4.sin_zero));
        dst_sap_sa4 = dst_sa4;
        dst_sap_sa4.sin_port = htons(SAP_PORT);
#ifdef HAVE_IPV6
    } else if (inet_pton(AF_INET6, dst_addr, &dst_sa6.sin6_addr) > 0) {
        dst_sa6.sin6_family = af = AF_INET6;
        dst_sa6.sin6_port = htons((uint16_t) port);
        dst_sa6.sin6_flowinfo = 0;
        dst_sa6.sin6_scope_id = 0;
        dst_sap_sa6 = dst_sa6;
        dst_sap_sa6.sin6_port = htons(SAP_PORT);
#endif
    } else {
        pa_log("Invalid destination '%s'", dst_addr);
        goto fail;
    }

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

    if (af == AF_INET && bind(fd, (struct sockaddr*) &src_sa4, sizeof(src_sa4)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && bind(fd, (struct sockaddr*) &src_sa6, sizeof(src_sa6)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    if (af == AF_INET && connect(fd, (struct sockaddr*) &dst_sa4, sizeof(dst_sa4)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && connect(fd, (struct sockaddr*) &dst_sa6, sizeof(dst_sa6)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    if ((sap_fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) {
        pa_log("socket() failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (af == AF_INET && bind(sap_fd, (struct sockaddr*) &src_sap_sa4, sizeof(src_sap_sa4)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && bind(sap_fd, (struct sockaddr*) &src_sap_sa6, sizeof(src_sap_sa6)) < 0) {
        pa_log("bind() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    if (af == AF_INET && connect(sap_fd, (struct sockaddr*) &dst_sap_sa4, sizeof(dst_sap_sa4)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#ifdef HAVE_IPV6
    } else if (af == AF_INET6 && connect(sap_fd, (struct sockaddr*) &dst_sap_sa6, sizeof(dst_sap_sa6)) < 0) {
        pa_log("connect() failed: %s", pa_cstrerror(errno));
        goto fail;
#endif
    }

    j = loop;
    if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &j, sizeof(j)) < 0 ||
        setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &j, sizeof(j)) < 0) {
        pa_log("IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno));
        goto fail;
    }

    if (ttl != DEFAULT_TTL) {
        int _ttl = (int) ttl;

        if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &_ttl, sizeof(_ttl)) < 0) {
            pa_log("IP_MULTICAST_TTL failed: %s", pa_cstrerror(errno));
            goto fail;
        }

        if (setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_TTL, &_ttl, sizeof(_ttl)) < 0) {
            pa_log("IP_MULTICAST_TTL (sap) failed: %s", pa_cstrerror(errno));
            goto fail;
        }
    }

    /* If the socket queue is full, let's drop packets */
    pa_make_fd_nonblock(fd);
    pa_make_udp_socket_low_delay(fd);

    pa_source_output_new_data_init(&data);
    pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream");
    pa_proplist_sets(data.proplist, "rtp.source", src_addr);
    pa_proplist_sets(data.proplist, "rtp.destination", dst_addr);
    pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu);
    pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port);
    pa_proplist_setf(data.proplist, "rtp.ttl", "%lu", (unsigned long) ttl);
    data.driver = __FILE__;
    data.module = m;
    pa_source_output_new_data_set_source(&data, s, false, true);
    pa_source_output_new_data_set_sample_spec(&data, &ss);
    pa_source_output_new_data_set_channel_map(&data, &cm);
    data.flags |= get_dont_inhibit_auto_suspend_flag(s, inhibit_auto_suspend);

    pa_source_output_new(&o, m->core, &data);
    pa_source_output_new_data_done(&data);

    if (!o) {
        pa_log("failed to create source output.");
        goto fail;
    }

    o->parent.process_msg = source_output_process_msg;
    o->push = source_output_push_cb;
    o->moving = source_output_moving_cb;
    o->kill = source_output_kill_cb;

    pa_log_info("Configured source latency of %llu ms.",
                (unsigned long long) pa_source_output_set_requested_latency(o, pa_bytes_to_usec(mtu, &o->sample_spec)) / PA_USEC_PER_MSEC);

    m->userdata = o->userdata = u = pa_xnew(struct userdata, 1);
    u->module = m;
    u->source_output = o;

    u->memblockq = pa_memblockq_new(
            "module-rtp-send memblockq",
            0,
            MEMBLOCKQ_MAXLENGTH,
            MEMBLOCKQ_MAXLENGTH,
            &ss,
            1,
            0,
            0,
            NULL);

    u->mtu = mtu;

    k = sizeof(sa_dst);
    pa_assert_se((r = getsockname(fd, (struct sockaddr*) &sa_dst, &k)) >= 0);

    n = pa_xstrdup(pa_modargs_get_value(ma, "stream_name", NULL));
    if (n == NULL)
        n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn)));

    if (af == AF_INET) {
        p = pa_sdp_build(af,
                     (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr,
                     (void*) &dst_sa4.sin_addr,
                     n, (uint16_t) port, payload, &ss);
#ifdef HAVE_IPV6
    } else {
        p = pa_sdp_build(af,
                     (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr,
                     (void*) &dst_sa6.sin6_addr,
                     n, (uint16_t) port, payload, &ss);
#endif
    }

    pa_xfree(n);

    pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss));
    pa_sap_context_init_send(&u->sap_context, sap_fd, p);

    pa_log_info("RTP stream initialized with mtu %u on %s:%u from %s ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dst_addr, port, src_addr, ttl, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
    pa_log_info("SDP-Data:\n%s\nEOF", p);

    pa_sap_send(&u->sap_context, 0);

    u->sap_event = pa_core_rttime_new(m->core, pa_rtclock_now() + SAP_INTERVAL, sap_event_cb, u);
    u->inhibit_auto_suspend = inhibit_auto_suspend;

    pa_source_output_put(u->source_output);

    pa_modargs_free(ma);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

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

    if (sap_fd >= 0)
        pa_close(sap_fd);

    return -1;
}
Beispiel #3
0
int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) {
    pa_strbuf *buf = NULL;
    int c;
    int b;

    pa_assert(conf);
    pa_assert(argc > 0);
    pa_assert(argv);

    buf = pa_strbuf_new();

    if (conf->script_commands)
        pa_strbuf_puts(buf, conf->script_commands);

    while ((c = getopt_long(argc, argv, "L:F:ChDnp:kv", long_options, NULL)) != -1) {
        switch (c) {
            case ARG_HELP:
            case 'h':
                conf->cmd = PA_CMD_HELP;
                break;

            case ARG_VERSION:
                conf->cmd = PA_CMD_VERSION;
                break;

            case ARG_DUMP_CONF:
                conf->cmd = PA_CMD_DUMP_CONF;
                break;

            case ARG_DUMP_MODULES:
                conf->cmd = PA_CMD_DUMP_MODULES;
                break;

            case ARG_DUMP_RESAMPLE_METHODS:
                conf->cmd = PA_CMD_DUMP_RESAMPLE_METHODS;
                break;

            case ARG_CLEANUP_SHM:
                conf->cmd = PA_CMD_CLEANUP_SHM;
                break;

            case 'k':
            case ARG_KILL:
                conf->cmd = PA_CMD_KILL;
                break;

            case ARG_START:
                conf->cmd = PA_CMD_START;
                conf->daemonize = true;
                break;

            case ARG_CHECK:
                conf->cmd = PA_CMD_CHECK;
                break;

            case ARG_LOAD:
            case 'L':
                pa_strbuf_printf(buf, "load-module %s\n", optarg);
                break;

            case ARG_FILE:
            case 'F': {
                char *p;
                pa_strbuf_printf(buf, ".include %s\n", p = pa_make_path_absolute(optarg));
                pa_xfree(p);
                break;
            }

            case 'C':
                pa_strbuf_puts(buf, "load-module module-cli exit_on_eof=1\n");
                break;

            case ARG_DAEMONIZE:
            case 'D':
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--daemonize expects boolean argument"));
                    goto fail;
                }
                conf->daemonize = !!b;
                break;

            case ARG_FAIL:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--fail expects boolean argument"));
                    goto fail;
                }
                conf->fail = !!b;
                break;

            case 'v':
            case ARG_LOG_LEVEL:

                if (optarg) {
                    if (pa_daemon_conf_set_log_level(conf, optarg) < 0) {
                        pa_log(_("--log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error)."));
                        goto fail;
                    }
                } else {
                    if (conf->log_level < PA_LOG_LEVEL_MAX-1)
                        conf->log_level++;
                }

                break;

            case ARG_HIGH_PRIORITY:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--high-priority expects boolean argument"));
                    goto fail;
                }
                conf->high_priority = !!b;
                break;

            case ARG_REALTIME:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--realtime expects boolean argument"));
                    goto fail;
                }
                conf->realtime_scheduling = !!b;
                break;

            case ARG_DISALLOW_MODULE_LOADING:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--disallow-module-loading expects boolean argument"));
                    goto fail;
                }
                conf->disallow_module_loading = !!b;
                break;

            case ARG_DISALLOW_EXIT:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--disallow-exit expects boolean argument"));
                    goto fail;
                }
                conf->disallow_exit = !!b;
                break;

            case ARG_USE_PID_FILE:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--use-pid-file expects boolean argument"));
                    goto fail;
                }
                conf->use_pid_file = !!b;
                break;

            case 'p':
            case ARG_DL_SEARCH_PATH:
                pa_xfree(conf->dl_search_path);
                conf->dl_search_path = pa_xstrdup(optarg);
                break;

            case 'n':
                conf->load_default_script_file = false;
                break;

            case ARG_LOG_TARGET:
                if (pa_daemon_conf_set_log_target(conf, optarg) < 0) {
#ifdef HAVE_SYSTEMD_JOURNAL
                    pa_log(_("Invalid log target: use either 'syslog', 'journal','stderr' or 'auto' or a valid file name 'file:<path>', 'newfile:<path>'."));
#else
                    pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto' or a valid file name 'file:<path>', 'newfile:<path>'."));
#endif
                    goto fail;
                }
                break;

            case ARG_LOG_TIME:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--log-time expects boolean argument"));
                    goto fail;
                }
                conf->log_time = !!b;
                break;

            case ARG_LOG_META:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--log-meta expects boolean argument"));
                    goto fail;
                }
                conf->log_meta = !!b;
                break;

            case ARG_LOG_BACKTRACE:
                conf->log_backtrace = (unsigned) atoi(optarg);
                break;

            case ARG_EXIT_IDLE_TIME:
                conf->exit_idle_time = atoi(optarg);
                break;

            case ARG_SCACHE_IDLE_TIME:
                conf->scache_idle_time = atoi(optarg);
                break;

            case ARG_RESAMPLE_METHOD:
                if (pa_daemon_conf_set_resample_method(conf, optarg) < 0) {
                    pa_log(_("Invalid resample method '%s'."), optarg);
                    goto fail;
                }
                break;

            case ARG_SYSTEM:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--system expects boolean argument"));
                    goto fail;
                }
                conf->system_instance = !!b;
                break;

            case ARG_NO_CPU_LIMIT:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--no-cpu-limit expects boolean argument"));
                    goto fail;
                }
                conf->no_cpu_limit = !!b;
                break;

            case ARG_DISABLE_SHM:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--disable-shm expects boolean argument"));
                    goto fail;
                }
                conf->disable_shm = !!b;
                break;

            case ARG_ENABLE_MEMFD:
                if ((b = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
                    pa_log(_("--enable-memfd expects boolean argument"));
                    goto fail;
                }
                conf->disable_memfd = !b;
                break;

            default:
                goto fail;
        }
    }

    pa_xfree(conf->script_commands);
    conf->script_commands = pa_strbuf_to_string_free(buf);

    *d = optind;

    return 0;

fail:
    if (buf)
        pa_strbuf_free(buf);

    return -1;
}
Beispiel #4
0
int main(int argc, char *argv[]) {
    pa_mainloop* m = NULL;
    int ret = 1, c;
    char *bn, *server = NULL;
    pa_time_event *time_event = NULL;
    const char *filename = NULL;
    /* type for pa_read/_write. passed as userdata to the callbacks */
    unsigned long type = 0;

    static const struct option long_options[] = {
        {"record",       0, NULL, 'r'},
        {"playback",     0, NULL, 'p'},
        {"device",       1, NULL, 'd'},
        {"server",       1, NULL, 's'},
        {"client-name",  1, NULL, 'n'},
        {"stream-name",  1, NULL, ARG_STREAM_NAME},
        {"version",      0, NULL, ARG_VERSION},
        {"help",         0, NULL, 'h'},
        {"verbose",      0, NULL, 'v'},
        {"volume",       1, NULL, ARG_VOLUME},
        {"rate",         1, NULL, ARG_SAMPLERATE},
        {"format",       1, NULL, ARG_SAMPLEFORMAT},
        {"channels",     1, NULL, ARG_CHANNELS},
        {"channel-map",  1, NULL, ARG_CHANNELMAP},
        {"fix-format",   0, NULL, ARG_FIX_FORMAT},
        {"fix-rate",     0, NULL, ARG_FIX_RATE},
        {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
        {"no-remap",     0, NULL, ARG_NO_REMAP},
        {"no-remix",     0, NULL, ARG_NO_REMIX},
        {"latency",      1, NULL, ARG_LATENCY},
        {"process-time", 1, NULL, ARG_PROCESS_TIME},
        {"property",     1, NULL, ARG_PROPERTY},
        {"raw",          0, NULL, ARG_RAW},
        {"passthrough",  0, NULL, ARG_PASSTHROUGH},
        {"file-format",  2, NULL, ARG_FILE_FORMAT},
        {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
        {"latency-msec", 1, NULL, ARG_LATENCY_MSEC},
        {"process-time-msec", 1, NULL, ARG_PROCESS_TIME_MSEC},
        {"monitor-stream", 1, NULL, ARG_MONITOR_STREAM},
        {NULL,           0, NULL, 0}
    };

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

    bn = pa_path_get_filename(argv[0]);

    if (strstr(bn, "play")) {
        mode = PLAYBACK;
        raw = false;
    } else if (strstr(bn, "record")) {
        mode = RECORD;
        raw = false;
    } else if (strstr(bn, "cat")) {
        mode = PLAYBACK;
        raw = true;
    } else if (strstr(bn, "rec") || strstr(bn, "mon")) {
        mode = RECORD;
        raw = true;
    }

    proplist = pa_proplist_new();

    while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {

        switch (c) {
            case 'h' :
                help(bn);
                ret = 0;
                goto quit;

            case ARG_VERSION:
                printf(_("pacat %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;

            case 'r':
                mode = RECORD;
                break;

            case 'p':
                mode = PLAYBACK;
                break;

            case 'd':
                pa_xfree(device);
                device = pa_xstrdup(optarg);
                break;

            case 's':
                pa_xfree(server);
                server = pa_xstrdup(optarg);
                break;

            case 'n': {
                char *t;

                if (!(t = pa_locale_to_utf8(optarg)) ||
                    pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {

                    pa_log(_("Invalid client name '%s'"), t ? t : optarg);
                    pa_xfree(t);
                    goto quit;
                }

                pa_xfree(t);
                break;
            }

            case ARG_STREAM_NAME: {
                char *t;

                if (!(t = pa_locale_to_utf8(optarg)) ||
                    pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) {

                    pa_log(_("Invalid stream name '%s'"), t ? t : optarg);
                    pa_xfree(t);
                    goto quit;
                }

                pa_xfree(t);
                break;
            }

            case 'v':
                verbose = 1;
                break;

            case ARG_VOLUME: {
                int v = atoi(optarg);
                volume = v < 0 ? 0U : (pa_volume_t) v;
                volume_is_set = true;
                break;
            }

            case ARG_CHANNELS:
                sample_spec.channels = (uint8_t) atoi(optarg);
                sample_spec_set = true;
                break;

            case ARG_SAMPLEFORMAT:
                sample_spec.format = pa_parse_sample_format(optarg);
                sample_spec_set = true;
                break;

            case ARG_SAMPLERATE:
                sample_spec.rate = (uint32_t) atoi(optarg);
                sample_spec_set = true;
                break;

            case ARG_CHANNELMAP:
                if (!pa_channel_map_parse(&channel_map, optarg)) {
                    pa_log(_("Invalid channel map '%s'"), optarg);
                    goto quit;
                }

                channel_map_set = true;
                break;

            case ARG_FIX_CHANNELS:
                flags |= PA_STREAM_FIX_CHANNELS;
                break;

            case ARG_FIX_RATE:
                flags |= PA_STREAM_FIX_RATE;
                break;

            case ARG_FIX_FORMAT:
                flags |= PA_STREAM_FIX_FORMAT;
                break;

            case ARG_NO_REMIX:
                flags |= PA_STREAM_NO_REMIX_CHANNELS;
                break;

            case ARG_NO_REMAP:
                flags |= PA_STREAM_NO_REMAP_CHANNELS;
                break;

            case ARG_LATENCY:
                if (((latency = (size_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid latency specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_PROCESS_TIME:
                if (((process_time = (size_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid process time specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_LATENCY_MSEC:
                if (((latency_msec = (int32_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid latency specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_PROCESS_TIME_MSEC:
                if (((process_time_msec = (int32_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid process time specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_PROPERTY: {
                char *t;

                if (!(t = pa_locale_to_utf8(optarg)) ||
                    pa_proplist_setp(proplist, t) < 0) {

                    pa_xfree(t);
                    pa_log(_("Invalid property '%s'"), optarg);
                    goto quit;
                }

                pa_xfree(t);
                break;
            }

            case ARG_RAW:
                raw = true;
                break;

            case ARG_PASSTHROUGH:
                flags |= PA_STREAM_PASSTHROUGH;
                break;

            case ARG_FILE_FORMAT:
                if (optarg) {
                    if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
                        pa_log(_("Unknown file format %s."), optarg);
                        goto quit;
                    }
                }

                raw = false;
                break;

            case ARG_LIST_FILE_FORMATS:
                pa_sndfile_dump_formats();
                ret = 0;
                goto quit;

            case ARG_MONITOR_STREAM:
                if (pa_atou(optarg, &monitor_stream) < 0) {
                    pa_log(_("Failed to parse the argument for --monitor-stream"));
                    goto quit;
                }
                break;

            default:
                goto quit;
        }
    }

    if (!pa_sample_spec_valid(&sample_spec)) {
        pa_log(_("Invalid sample specification"));
        goto quit;
    }

    if (optind+1 == argc) {
        int fd;

        filename = argv[optind];

        if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
            pa_log(_("open(): %s"), strerror(errno));
            goto quit;
        }

        if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
            pa_log(_("dup2(): %s"), strerror(errno));
            goto quit;
        }

        pa_close(fd);

    } else if (optind+1 <= argc) {
        pa_log(_("Too many arguments."));
        goto quit;
    }

    if (!raw) {
        SF_INFO sfi;
        pa_zero(sfi);

        if (mode == RECORD) {
            /* This might patch up the sample spec */
            if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
                pa_log(_("Failed to generate sample specification for file."));
                goto quit;
            }

            if (file_format <= 0) {
                char *extension;
                if (filename && (extension = strrchr(filename, '.')))
                    file_format = pa_sndfile_format_from_string(extension+1);
                if (file_format <= 0)
                    file_format = SF_FORMAT_WAV;
                /* Transparently upgrade classic .wav to wavex for multichannel audio */
                if (file_format == SF_FORMAT_WAV &&
                    (sample_spec.channels > 2 ||
                    (channel_map_set &&
                    !(sample_spec.channels == 1 && channel_map.map[0] == PA_CHANNEL_POSITION_MONO) &&
                    !(sample_spec.channels == 2 && channel_map.map[0] == PA_CHANNEL_POSITION_LEFT
                                                && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))))
                    file_format = SF_FORMAT_WAVEX;
            }

            sfi.format |= file_format;
        }

        if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
                                   mode == RECORD ? SFM_WRITE : SFM_READ,
                                   &sfi, 0))) {
            pa_log(_("Failed to open audio file."));
            goto quit;
        }

        if (mode == PLAYBACK) {
            if (sample_spec_set)
                pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));

            if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
                pa_log(_("Failed to determine sample specification from file."));
                goto quit;
            }
            sample_spec_set = true;

            if (!channel_map_set) {
                /* Allow the user to overwrite the channel map on the command line */
                if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
                    if (sample_spec.channels > 2)
                        pa_log(_("Warning: Failed to determine channel map from file."));
                } else
                    channel_map_set = true;
            }
        }
    }

    if (!channel_map_set)
        pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);

    if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
        pa_log(_("Channel map doesn't match sample specification"));
        goto quit;
    }

    if (!raw) {
        pa_proplist *sfp;

        if (mode == PLAYBACK)
            readf_function = pa_sndfile_readf_function(&sample_spec);
        else {
            if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
                pa_log(_("Warning: failed to write channel map to file."));

            writef_function = pa_sndfile_writef_function(&sample_spec);
        }

        /* Fill in libsndfile prop list data */
        sfp = pa_proplist_new();
        pa_sndfile_init_proplist(sndfile, sfp);
        pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
        pa_proplist_free(sfp);
    }

    if (verbose) {
        char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];

        pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
                mode == RECORD ? _("recording") : _("playback"),
                pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
                pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
    }

    /* Fill in client name if none was set */
    if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
        char *t;

        if ((t = pa_locale_to_utf8(bn))) {
            pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
            pa_xfree(t);
        }
    }

    /* Fill in media name if none was set */
    if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
        const char *t;

        if ((t = filename) ||
            (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
            pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);

        if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
            pa_log(_("Failed to set media name."));
            goto quit;
        }
    }

    /* Set up a new main loop */
    if (!(m = pa_mainloop_new())) {
        pa_log(_("pa_mainloop_new() failed."));
        goto quit;
    }

    mainloop_api = pa_mainloop_get_api(m);

    pa_assert_se(pa_signal_init(mainloop_api) == 0);
    pa_signal_new(SIGINT, exit_signal_callback, NULL);
    pa_signal_new(SIGTERM, exit_signal_callback, NULL);
#ifdef SIGUSR1
    pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
#endif
    pa_disable_sigpipe();

    if (raw) {
#ifdef OS_IS_WIN32
        /* need to turn on binary mode for stdio io. Windows, meh */
        setmode(mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, O_BINARY);
#endif
        if (!(stdio_event = mainloop_api->io_new(mainloop_api,
                                                 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
                                                 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
                                                 mode == PLAYBACK ? stdin_callback : stdout_callback, &type))) {
            pa_log(_("io_new() failed."));
            goto quit;
        }
    }

    /* Create a new connection context */
    if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
        pa_log(_("pa_context_new() failed."));
        goto quit;
    }

    pa_context_set_state_callback(context, context_state_callback, NULL);

    /* Connect the context */
    if (pa_context_connect(context, server, 0, NULL) < 0) {
        pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
        goto quit;
    }

    if (verbose) {
        if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
            pa_log(_("pa_context_rttime_new() failed."));
            goto quit;
        }
    }

    /* Run the main loop */
    if (pa_mainloop_run(m, &ret) < 0) {
        pa_log(_("pa_mainloop_run() failed."));
        goto quit;
    }

quit:
    if (stream)
        pa_stream_unref(stream);

    if (context)
        pa_context_unref(context);

    if (stdio_event) {
        pa_assert(mainloop_api);
        mainloop_api->io_free(stdio_event);
    }

    if (time_event) {
        pa_assert(mainloop_api);
        mainloop_api->time_free(time_event);
    }

    if (m) {
        pa_signal_done();
        pa_mainloop_free(m);
    }

    pa_xfree(silence_buffer);
    pa_xfree(buffer);

    pa_xfree(server);
    pa_xfree(device);

    if (sndfile)
        sf_close(sndfile);

    if (proplist)
        pa_proplist_free(proplist);

    return ret;
}
static void context_state_cb(pa_context *c, void *userdata) {
    struct userdata *u = userdata;
    pa_assert(u);

    switch (pa_context_get_state(c)) {
        case PA_CONTEXT_UNCONNECTED:
        case PA_CONTEXT_CONNECTING:
        case PA_CONTEXT_AUTHORIZING:
        case PA_CONTEXT_SETTING_NAME:
            break;
        case PA_CONTEXT_READY: {
            pa_proplist *proplist;
            pa_buffer_attr bufferattr;
            pa_usec_t requested_latency;
            char *username = pa_get_user_name_malloc();
            char *hostname = pa_get_host_name_malloc();
            /* TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' */
            char *stream_name = pa_sprintf_malloc(_("Tunnel for %s@%s"), username, hostname);
            pa_xfree(hostname);
            pa_xfree(username);

            pa_log_debug("Connection successful. Creating stream.");
            pa_assert(!u->stream);

            proplist = tunnel_new_proplist(u);
            
            if(u->transcode.encoding != -1) {
            
                  unsigned int n_formats = 1;
                  pa_format_info *formats[1];
  
                  formats[0] = pa_format_info_new();
                  formats[0]->encoding = u->transcode.encoding;
                  pa_format_info_set_sample_format(formats[0], u->sink->sample_spec.format);
                  pa_format_info_set_rate(formats[0], u->sink->sample_spec.rate);
                  pa_format_info_set_channels(formats[0], u->sink->sample_spec.channels);
                  pa_format_info_set_channel_map(formats[0],  &u->sink->channel_map);
                  pa_transcode_set_format_info(&u->transcode, formats[0]);

                  u->stream = pa_stream_new_extended(u->context, stream_name, formats, n_formats, proplist);
                       
            }
            else
                  u->stream = pa_stream_new_with_proplist(u->context,
                                                    stream_name,
                                                    &u->sink->sample_spec,
                                                    &u->sink->channel_map,
                                                    proplist);
            pa_proplist_free(proplist);
            pa_xfree(stream_name);

            if (!u->stream) {
                pa_log_error("Could not create a stream.");
                u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
                return;
            }

            requested_latency = pa_sink_get_requested_latency_within_thread(u->sink);
            if (requested_latency == (pa_usec_t) -1)
                requested_latency = u->sink->thread_info.max_latency;

            reset_bufferattr(&bufferattr);
            bufferattr.tlength = pa_usec_to_bytes(requested_latency, &u->sink->sample_spec);

            pa_stream_set_state_callback(u->stream, stream_state_cb, userdata);
            pa_stream_set_buffer_attr_callback(u->stream, stream_changed_buffer_attr_cb, userdata);
            if (pa_stream_connect_playback(u->stream,
                                           u->remote_sink_name,
                                           &bufferattr,
                                           PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_DONT_MOVE | PA_STREAM_START_CORKED | PA_STREAM_AUTO_TIMING_UPDATE,
                                           NULL,
                                           NULL) < 0) {
                pa_log_error("Could not connect stream.");
                u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
            }
            u->connected = true;
            break;
        }
        case PA_CONTEXT_FAILED:
            pa_log_debug("Context failed: %s.", pa_strerror(pa_context_errno(u->context)));
            u->connected = false;
            u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
            break;
        case PA_CONTEXT_TERMINATED:
            pa_log_debug("Context terminated.");
            u->connected = false;
            u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
            break;
    }
}
Beispiel #6
0
pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
    pa_module *m = NULL;
    pa_bool_t (*load_once)(void);
    const char* (*get_deprecated)(void);
    pa_modinfo *mi;

    pa_assert(c);
    pa_assert(name);

    if (c->disallow_module_loading)
        goto fail;

    m = pa_xnew(pa_module, 1);
    m->name = pa_xstrdup(name);
    m->argument = pa_xstrdup(argument);
    m->load_once = FALSE;
    m->proplist = pa_proplist_new();

    if (!(m->dl = lt_dlopenext(name))) {
        pa_log("Failed to open module \"%s\": %s", name, lt_dlerror());
        goto fail;
    }

    if ((load_once = (pa_bool_t (*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_LOAD_ONCE))) {

        m->load_once = load_once();

        if (m->load_once) {
            pa_module *i;
            uint32_t idx;
            /* OK, the module only wants to be loaded once, let's make sure it is */

            for (i = pa_idxset_first(c->modules, &idx); i; i = pa_idxset_next(c->modules, &idx)) {
                if (strcmp(name, i->name) == 0) {
                    pa_log("Module \"%s\" should be loaded once at most. Refusing to load.", name);
                    goto fail;
                }
            }
        }
    }

    if ((get_deprecated = (const char* (*) (void)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_DEPRECATE))) {
        const char *t;

        if ((t = get_deprecated()))
            pa_log_warn("%s is deprecated: %s", name, t);
    }

    if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) {
        pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name);
        goto fail;
    }

    m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE);
    m->get_n_used = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_N_USED);
    m->userdata = NULL;
    m->core = c;
    m->unload_requested = FALSE;

    if (m->init(m) < 0) {
        pa_log_error("Failed to load  module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
        goto fail;
    }

    pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0);
    pa_assert(m->index != PA_IDXSET_INVALID);

    pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : "");

    pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index);

    if ((mi = pa_modinfo_get_by_handle(m->dl, name))) {

        if (mi->author && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_AUTHOR))
            pa_proplist_sets(m->proplist, PA_PROP_MODULE_AUTHOR, mi->author);

        if (mi->description && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_DESCRIPTION))
            pa_proplist_sets(m->proplist, PA_PROP_MODULE_DESCRIPTION, mi->description);

        if (mi->version && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_VERSION))
            pa_proplist_sets(m->proplist, PA_PROP_MODULE_VERSION, mi->version);

        pa_modinfo_free(mi);
    }

    return m;

fail:

    if (m) {
        if (m->proplist)
            pa_proplist_free(m->proplist);

        pa_xfree(m->argument);
        pa_xfree(m->name);

        if (m->dl)
            lt_dlclose(m->dl);

        pa_xfree(m);
    }

    return NULL;
}
static void verify_access(struct userdata *u, struct device *d) {
    char *cd;
    pa_card *card;
    bool accessible;

    pa_assert(u);
    pa_assert(d);

    cd = pa_sprintf_malloc("/dev/snd/controlC%s", path_get_card_id(d->path));
    accessible = access(cd, R_OK|W_OK) >= 0;
    pa_log_debug("%s is accessible: %s", cd, pa_yes_no(accessible));

    pa_xfree(cd);

    if (d->module == PA_INVALID_INDEX) {

        /* If we are not loaded, try to load */

        if (accessible) {
            pa_module *m;
            bool busy;

            /* Check if any of the PCM devices that belong to this
             * card are currently busy. If they are, don't try to load
             * right now, to make sure the probing phase can
             * successfully complete. When the current user of the
             * device closes it we will get another notification via
             * inotify and can then recheck. */

            busy = is_card_busy(path_get_card_id(d->path));
            pa_log_debug("%s is busy: %s", d->path, pa_yes_no(busy));

            if (!busy) {

                /* So, why do we rate limit here? It's certainly ugly,
                 * but there seems to be no other way. Problem is
                 * this: if we are unable to configure/probe an audio
                 * device after opening it we will close it again and
                 * the module initialization will fail. This will then
                 * cause an inotify event on the device node which
                 * will be forwarded to us. We then try to reopen the
                 * audio device again, practically entering a busy
                 * loop.
                 *
                 * A clean fix would be if we would be able to ignore
                 * our own inotify close events. However, inotify
                 * lacks such functionality. Also, during probing of
                 * the device we cannot really distinguish between
                 * other processes causing EBUSY or ourselves, which
                 * means we have no way to figure out if the probing
                 * during opening was canceled by a "try again"
                 * failure or a "fatal" failure. */

                if (pa_ratelimit_test(&d->ratelimit, PA_LOG_DEBUG)) {
                    pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args);
                    m = pa_module_load(u->core, "module-alsa-card", d->args);

                    if (m) {
                        d->module = m->index;
                        pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name);
                    } else
                        pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name);
                } else
                    pa_log_warn("Tried to configure %s (%s) more often than %u times in %llus",
                                d->path,
                                d->card_name,
                                d->ratelimit.burst,
                                (long long unsigned) (d->ratelimit.interval / PA_USEC_PER_SEC));
            }
        }

    } else {

        /* If we are already loaded update suspend status with
         * accessible boolean */

        if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD))) {
            pa_log_debug("%s all sinks and sources of card %s.", accessible ? "Resuming" : "Suspending", d->card_name);
            pa_card_suspend(card, !accessible, PA_SUSPEND_SESSION);
        }
    }
}
Beispiel #8
0
pa_reserve_monitor_wrapper* pa_reserve_monitor_wrapper_get(pa_core *c, const char *device_name) {
    pa_reserve_monitor_wrapper *w;
    int k;
    char *t;
#ifdef HAVE_DBUS
    DBusError error;

    dbus_error_init(&error);
#endif

    pa_assert(c);
    pa_assert(device_name);

    t = pa_sprintf_malloc("reserve-monitor-wrapper@%s", device_name);

    if ((w = pa_shared_get(c, t))) {
        pa_xfree(t);

        pa_assert(PA_REFCNT_VALUE(w) >= 1);
        PA_REFCNT_INC(w);

        return w;
    }

    w = pa_xnew0(pa_reserve_monitor_wrapper, 1);
    PA_REFCNT_INIT(w);
    w->core = c;
    pa_hook_init(&w->hook, w);
    w->shared_name = t;

    pa_assert_se(pa_shared_set(c, w->shared_name, w) >= 0);

#ifdef HAVE_DBUS
    if (!(w->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);

        /* We don't treat this as error here because we want allow PA
         * to run even when no session bus is available. */
        return w;
    }

    if ((k = rm_watch(
                 &w->monitor,
                 pa_dbus_connection_get(w->connection),
                 device_name,
                 change_cb,
                 NULL)) < 0) {

        pa_log_debug("Failed to create watch on device '%s': %s", device_name, pa_cstrerror(-k));
        goto fail;
    }

    pa_log_debug("Successfully create reservation lock monitor for device '%s'", device_name);

    rm_set_userdata(w->monitor, w);
    return w;

fail:
    dbus_error_free(&error);

    reserve_monitor_wrapper_free(w);

    return NULL;
#else
    return w;
#endif
}
Beispiel #9
0
static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
    pa_xfree(userdata);
}
Beispiel #10
0
pa_source *pa_droid_source_new(pa_module *m,
                                 pa_modargs *ma,
                                 const char *driver,
                                 pa_droid_card_data *card_data,
                                 pa_droid_mapping *am,
                                 pa_card *card) {

    struct userdata *u = NULL;
    char *thread_name = NULL;
    pa_source_new_data data;
    const char *module_id = NULL;
    /* const char *tmp; */
    uint32_t sample_rate;
    uint32_t alternate_sample_rate;
    audio_devices_t dev_in;
    pa_sample_spec sample_spec;
    pa_channel_map channel_map;
    bool namereg_fail = false;
    pa_droid_config_audio *config = NULL; /* Only used when source is created without card */
    uint32_t source_buffer = 0;
    char audio_source[32];
    int ret;

    audio_format_t hal_audio_format = 0;
    audio_channel_mask_t hal_channel_mask = 0;

    pa_assert(m);
    pa_assert(ma);
    pa_assert(driver);

    /* When running under card use hw module name for source by default. */
    if (card && ma)
        module_id = am->input->module->name;
    else
        module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);

    sample_spec = m->core->default_sample_spec;
    channel_map = m->core->default_channel_map;

    if (pa_modargs_get_sample_spec_and_channel_map(ma, &sample_spec, &channel_map, PA_CHANNEL_MAP_AIFF) < 0) {
        pa_log("Failed to parse sample specification and channel map.");
        goto fail;
    }

    alternate_sample_rate = m->core->alternate_sample_rate;
    if (pa_modargs_get_alternate_sample_rate(ma, &alternate_sample_rate) < 0) {
        pa_log("Failed to parse alternate sample rate.");
        goto fail;
    }

    if (pa_modargs_get_value_u32(ma, "source_buffer", &source_buffer) < 0) {
        pa_log("Failed to parse source_buffer. Needs to be integer >= 0.");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    u->card = card;
    u->rtpoll = pa_rtpoll_new();
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);

    /* Enabled routing changes by default. */
    u->routing_changes_enabled = true;

    if (card_data) {
        pa_assert(card);
        u->card_data = card_data;
        pa_assert_se((u->hw_module = pa_droid_hw_module_get(u->core, NULL, card_data->module_id)));
    } else {
        /* Stand-alone source */

        if (!(config = pa_droid_config_load(ma)))
            goto fail;

        /* Ownership of config transfers to hw_module if opening of hw module succeeds. */
        if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
            goto fail;
    }

    if (!pa_convert_format(sample_spec.format, CONV_FROM_PA, &hal_audio_format)) {
        pa_log("Sample spec format %u not supported.", sample_spec.format);
        goto fail;
    }

    for (int i = 0; i < channel_map.channels; i++) {
        audio_channel_mask_t c;
        if (!pa_convert_input_channel(channel_map.map[i], CONV_FROM_PA, &c)) {
            pa_log("Failed to convert channel map.");
            goto fail;
        }
        hal_channel_mask |= c;
    }

    struct audio_config config_in = {
        .sample_rate = sample_spec.rate,
        .channel_mask = hal_channel_mask,
        .format = hal_audio_format
    };

    /* Default routing */
    /* FIXME So while setting routing through stream with HALv2 API fails, creation of stream
     * requires HALv2 style device to work properly. So until that oddity is resolved we always
     * set AUDIO_DEVICE_IN_BUILTIN_MIC as initial device here. */
#if 0
    pa_assert_se(pa_string_convert_input_device_str_to_num("AUDIO_DEVICE_IN_BUILTIN_MIC", &dev_in));

    if ((tmp = pa_modargs_get_value(ma, "input_devices", NULL))) {
        audio_devices_t tmp_dev;

        if (parse_device_list(tmp, &tmp_dev) && tmp_dev)
            dev_in = tmp_dev;

        pa_log_debug("Set initial devices %s", tmp);
    }
#else
    pa_log_info("FIXME: Setting AUDIO_DEVICE_IN_BUILTIN_MIC as initial device.");
    dev_in = AUDIO_DEVICE_IN_BUILTIN_MIC;
#endif
    pa_droid_hw_module_lock(u->hw_module);
    ret = u->hw_module->device->open_input_stream(u->hw_module->device,
                                                  u->hw_module->stream_in_id,
                                                  dev_in,
                                                  &config_in,
                                                  &u->stream);
    /* On some devices the first call will fail if the config parameters are
     * not supported, but it'll automatically set the right ones, expecting
     * the caller to call it again, so let's try at least one more time */
    if (!u->stream)
        ret = u->hw_module->device->open_input_stream(u->hw_module->device,
                                                      u->hw_module->stream_in_id,
                                                      dev_in,
                                                      &config_in,
                                                      &u->stream);

    u->hw_module->stream_in_id++;
    pa_droid_hw_module_unlock(u->hw_module);

    if (ret < 0) {
        pa_log("Failed to open input stream.");
        goto fail;
    }

    if ((sample_rate = u->stream->common.get_sample_rate(&u->stream->common)) != sample_spec.rate) {
        pa_log_warn("Requested sample rate %u but got %u instead.", sample_spec.rate, sample_rate);
        sample_spec.rate = sample_rate;
    }

    u->buffer_size = u->stream->common.get_buffer_size(&u->stream->common);
    if (source_buffer) {
        if (source_buffer < u->buffer_size)
            pa_log_warn("Requested buffer size %u less than HAL reported buffer size (%u).", source_buffer, u->buffer_size);
        else if (source_buffer % u->buffer_size) {
            uint32_t trunc = (source_buffer / u->buffer_size) * u->buffer_size;
            pa_log_warn("Requested buffer size %u not multiple of HAL buffer size (%u). Using buffer size %u", source_buffer, u->buffer_size, trunc);
            u->buffer_size = trunc;
        } else {
            pa_log_info("Using requested buffer size %u.", source_buffer);
            u->buffer_size = source_buffer;
        }
    }

    pa_log_info("Created Android stream with device: %u sample rate: %u channel mask: %u format: %u buffer size: %u",
            dev_in,
            sample_rate,
            config_in.channel_mask,
            config_in.format,
            u->buffer_size);

    /* Setting audio source to MIC by default */
    pa_snprintf(audio_source, sizeof(audio_source), "%s=%u", AUDIO_PARAMETER_STREAM_INPUT_SOURCE, AUDIO_SOURCE_MIC);
    u->stream->common.set_parameters(&u->stream->common, audio_source);
    pa_log_debug("Setting audio source to AUDIO_SOURCE_MIC by default");

    pa_source_new_data_init(&data);
    data.driver = driver;
    data.module = m;
    data.card = card;

    source_set_name(ma, &data, module_id);

    /* We need to give pa_modargs_get_value_boolean() a pointer to a local
     * variable instead of using &data.namereg_fail directly, because
     * data.namereg_fail is a bitfield and taking the address of a bitfield
     * variable is impossible. */
    namereg_fail = data.namereg_fail;
    if (pa_modargs_get_value_boolean(ma, "namereg_fail", &namereg_fail) < 0) {
        pa_log("Failed to parse namereg_fail argument.");
        pa_source_new_data_done(&data);
        goto fail;
    }
    data.namereg_fail = namereg_fail;

    pa_source_new_data_set_sample_spec(&data, &sample_spec);
    pa_source_new_data_set_channel_map(&data, &channel_map);
    pa_source_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);

    if (am)
        pa_droid_add_ports(data.ports, am, card);

    u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE);
    pa_source_new_data_done(&data);

    if (!u->source) {
        pa_log("Failed to create source.");
        goto fail;
    }

    u->source->userdata = u;

    u->source->parent.process_msg = source_process_msg;

    source_set_mute_control(u);

    u->source->set_port = source_set_port_cb;

    pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
    pa_source_set_rtpoll(u->source, u->rtpoll);

    /* Disable rewind for droid source */
    pa_source_set_max_rewind(u->source, 0);

    thread_name = pa_sprintf_malloc("droid-source-%s", module_id);
    if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) {
        pa_log("Failed to create thread.");
        goto fail;
    }
    pa_xfree(thread_name);
    thread_name = NULL;

    pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &sample_spec));
    pa_log_debug("Set fixed latency %" PRIu64 " usec", pa_bytes_to_usec(u->buffer_size, &sample_spec));

    if (u->source->active_port)
        source_set_port_cb(u->source, u->source->active_port);

    pa_source_put(u->source);

    return u->source;

fail:
    pa_xfree(thread_name);

    if (config)
        pa_xfree(config);

    if (u)
        userdata_free(u);

    return NULL;
}

void pa_droid_source_free(pa_source *s) {
    struct userdata *u;

    pa_source_assert_ref(s);
    pa_assert_se(u = s->userdata);

    userdata_free(u);
}

static void userdata_free(struct userdata *u) {

    if (u->source)
        pa_source_unlink(u->source);

    if (u->thread) {
        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
        pa_thread_free(u->thread);
    }

    pa_thread_mq_done(&u->thread_mq);

    if (u->source)
        pa_source_unref(u->source);

    if (u->memchunk.memblock)
        pa_memblock_unref(u->memchunk.memblock);

    if (u->hw_module && u->stream) {
        pa_droid_hw_module_lock(u->hw_module);
        u->hw_module->device->close_input_stream(u->hw_module->device, u->stream);
        pa_droid_hw_module_unlock(u->hw_module);
    }

    // Stand alone source
    if (u->hw_module)
        pa_droid_hw_module_unref(u->hw_module);

    pa_xfree(u);
}
Beispiel #11
0
pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name) {
    pa_reserve_wrapper *r;
    int k;
    char *t;
#ifdef HAVE_DBUS
    DBusError error;

    dbus_error_init(&error);
#endif

    pa_assert(c);
    pa_assert(device_name);

    t = pa_sprintf_malloc("reserve-wrapper@%s", device_name);

    if ((r = pa_shared_get(c, t))) {
        pa_xfree(t);

        pa_assert(PA_REFCNT_VALUE(r) >= 1);
        PA_REFCNT_INC(r);

        return r;
    }

    r = pa_xnew0(pa_reserve_wrapper, 1);
    PA_REFCNT_INIT(r);
    r->core = c;
    pa_hook_init(&r->hook, r);
    r->shared_name = t;

    pa_assert_se(pa_shared_set(c, r->shared_name, r) >= 0);

#ifdef HAVE_DBUS
    if (!(r->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);

        /* We don't treat this as error here because we want allow PA
         * to run even when no session bus is available. */
        return r;
    }

    if ((k = rd_acquire(
                 &r->device,
                 pa_dbus_connection_get(r->connection),
                 device_name,
                 _("PulseAudio Sound Server"),
                 0,
                 request_cb,
                 NULL)) < 0) {

        if (k == -EBUSY) {
            pa_log_debug("Device '%s' already locked.", device_name);
            goto fail;
        } else {
            pa_log_debug("Failed to acquire reservation lock on device '%s': %s", device_name, pa_cstrerror(-k));
            return r;
        }
    }

    pa_log_debug("Successfully acquired reservation lock on device '%s'", device_name);

    rd_set_userdata(r->device, r);

    return r;
fail:
    dbus_error_free(&error);

    reserve_wrapper_free(r);

    return NULL;
#else
    return r;
#endif
}
Beispiel #12
0
void pa_source_new_data_set_port(pa_source_new_data *data, const char *port) {
    pa_assert(data);

    pa_xfree(data->active_port);
    data->active_port = pa_xstrdup(port);
}
Beispiel #13
0
void pa_source_new_data_set_name(pa_source_new_data *data, const char *name) {
    pa_assert(data);

    pa_xfree(data->name);
    data->name = pa_xstrdup(name);
}
Beispiel #14
0
/* Called from main context */
pa_source* pa_source_new(
        pa_core *core,
        pa_source_new_data *data,
        pa_source_flags_t flags) {

    pa_source *s;
    const char *name;
    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
    char *pt;

    pa_assert(core);
    pa_assert(data);
    pa_assert(data->name);
    pa_assert_ctl_context();

    s = pa_msgobject_new(pa_source);

    if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
        pa_log_debug("Failed to register name %s.", data->name);
        pa_xfree(s);
        return NULL;
    }

    pa_source_new_data_set_name(data, name);

    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_NEW], data) < 0) {
        pa_xfree(s);
        pa_namereg_unregister(core, name);
        return NULL;
    }

    /* FIXME, need to free s here on failure */

    pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
    pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);

    pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));

    if (!data->channel_map_is_set)
        pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));

    pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
    pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);

    if (!data->volume_is_set)
        pa_cvolume_reset(&data->volume, data->sample_spec.channels);

    pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
    pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));

    if (!data->muted_is_set)
        data->muted = FALSE;

    if (data->card)
        pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);

    pa_device_init_description(data->proplist);
    pa_device_init_icon(data->proplist, FALSE);
    pa_device_init_intended_roles(data->proplist);

    if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
        pa_xfree(s);
        pa_namereg_unregister(core, name);
        return NULL;
    }

    s->parent.parent.free = source_free;
    s->parent.process_msg = pa_source_process_msg;

    s->core = core;
    s->state = PA_SOURCE_INIT;
    s->flags = flags;
    s->priority = 0;
    s->suspend_cause = 0;
    s->name = pa_xstrdup(name);
    s->proplist = pa_proplist_copy(data->proplist);
    s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
    s->module = data->module;
    s->card = data->card;

    s->priority = pa_device_init_priority(s->proplist);

    s->sample_spec = data->sample_spec;
    s->channel_map = data->channel_map;

    s->outputs = pa_idxset_new(NULL, NULL);
    s->n_corked = 0;
    s->monitor_of = NULL;
    s->output_from_master = NULL;

    s->volume = data->volume;
    pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
    s->base_volume = PA_VOLUME_NORM;
    s->n_volume_steps = PA_VOLUME_NORM+1;
    s->muted = data->muted;
    s->refresh_volume = s->refresh_muted = FALSE;

    reset_callbacks(s);
    s->userdata = NULL;

    s->asyncmsgq = NULL;

    /* As a minor optimization we just steal the list instead of
     * copying it here */
    s->ports = data->ports;
    data->ports = NULL;

    s->active_port = NULL;
    s->save_port = FALSE;

    if (data->active_port && s->ports)
        if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
            s->save_port = data->save_port;

    if (!s->active_port && s->ports) {
        void *state;
        pa_device_port *p;

        PA_HASHMAP_FOREACH(p, s->ports, state)
            if (!s->active_port || p->priority > s->active_port->priority)
                s->active_port = p;
    }
Beispiel #15
0
int pa__init(pa_module*m) {

    struct audio_buf_info info;
    struct userdata *u = NULL;
    const char *dev;
    int fd = -1;
    int nfrags, orig_frag_size, frag_size;
    int mode, caps;
    bool record = true, playback = true, use_mmap = true;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma = NULL;
    char hwdesc[64];
    const char *name;
    bool namereg_fail;
    pa_sink_new_data sink_new_data;
    pa_source_new_data source_new_data;

    pa_assert(m);

    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
        pa_log("Failed to parse module arguments.");
        goto fail;
    }

    if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
        pa_log("record= and playback= expect boolean argument.");
        goto fail;
    }

    if (!playback && !record) {
        pa_log("Neither playback nor record enabled for device.");
        goto fail;
    }

    mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));

    ss = m->core->default_sample_spec;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) {
        pa_log("Failed to parse sample specification or channel map");
        goto fail;
    }

    nfrags = (int) m->core->default_n_fragments;
    frag_size = (int) pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss);
    if (frag_size <= 0)
        frag_size = (int) pa_frame_size(&ss);

    if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) {
        pa_log("Failed to parse fragments arguments");
        goto fail;
    }

    if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) {
        pa_log("Failed to parse mmap argument.");
        goto fail;
    }

    if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0)
        goto fail;

    if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) {
        pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode.");
        use_mmap = false;
    }

    if (use_mmap && mode == O_WRONLY) {
        pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode.");
        use_mmap = false;
    }

    if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0)
        pa_log_info("Hardware name is '%s'.", hwdesc);
    else
        hwdesc[0] = 0;

    pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));

    orig_frag_size = frag_size;
    if (nfrags >= 2 && frag_size >= 1)
        if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0)
            goto fail;

    if (pa_oss_auto_format(fd, &ss) < 0)
        goto fail;

    if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
        pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno));
        goto fail;
    }
    pa_assert(frag_size > 0);

    u = pa_xnew0(struct userdata, 1);
    u->core = m->core;
    u->module = m;
    m->userdata = u;
    u->fd = fd;
    u->mixer_fd = -1;
    u->mixer_devmask = 0;
    u->use_getospace = u->use_getispace = true;
    u->use_getodelay = true;
    u->mode = mode;
    u->frame_size = pa_frame_size(&ss);
    u->device_name = pa_xstrdup(dev);
    u->in_nfrags = u->out_nfrags = (uint32_t) (u->nfrags = nfrags);
    u->out_fragment_size = u->in_fragment_size = (uint32_t) (u->frag_size = frag_size);
    u->orig_frag_size = orig_frag_size;
    u->use_mmap = use_mmap;
    u->rtpoll = pa_rtpoll_new();

    if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) {
        pa_log("pa_thread_mq_init() failed.");
        goto fail;
    }

    u->rtpoll_item = NULL;
    build_pollfd(u);

    if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
        pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize);
        u->in_fragment_size = (uint32_t) info.fragsize;
        u->in_nfrags = (uint32_t) info.fragstotal;
        u->use_getispace = true;
    }

    if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
        pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize);
        u->out_fragment_size = (uint32_t) info.fragsize;
        u->out_nfrags = (uint32_t) info.fragstotal;
        u->use_getospace = true;
    }

    u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size;
    u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size;

    if (mode != O_WRONLY) {
        char *name_buf = NULL;

        if (use_mmap) {
            if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
                pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno));
                use_mmap = u->use_mmap = false;
                u->in_mmap = NULL;
            } else
                pa_log_debug("Successfully mmap()ed input buffer.");
        }

        if ((name = pa_modargs_get_value(ma, "source_name", NULL)))
            namereg_fail = true;
        else {
            name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev));
            namereg_fail = false;
        }

        pa_source_new_data_init(&source_new_data);
        source_new_data.driver = __FILE__;
        source_new_data.module = m;
        pa_source_new_data_set_name(&source_new_data, name);
        source_new_data.namereg_fail = namereg_fail;
        pa_source_new_data_set_sample_spec(&source_new_data, &ss);
        pa_source_new_data_set_channel_map(&source_new_data, &map);
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, dev);
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "oss");
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, hwdesc[0] ? hwdesc : dev);
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, use_mmap ? "mmap" : "serial");
        pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) (u->in_hwbuf_size));
        pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE, "%lu", (unsigned long) (u->in_fragment_size));

        if (pa_modargs_get_proplist(ma, "source_properties", source_new_data.proplist, PA_UPDATE_REPLACE) < 0) {
            pa_log("Invalid properties");
            pa_source_new_data_done(&source_new_data);
            pa_xfree(name_buf);
            goto fail;
        }

        u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY);
        pa_source_new_data_done(&source_new_data);
        pa_xfree(name_buf);

        if (!u->source) {
            pa_log("Failed to create source object");
            goto fail;
        }

        u->source->parent.process_msg = source_process_msg;
        u->source->userdata = u;

        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
        pa_source_set_rtpoll(u->source, u->rtpoll);
        pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->in_hwbuf_size, &u->source->sample_spec));
        u->source->refresh_volume = true;

        if (use_mmap)
            u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags);
    }
Beispiel #16
0
int pa__init(pa_module*m) {
    struct userdata *u;
    pa_sample_spec ss;
    pa_channel_map map;
    pa_modargs *ma;
    char *t;
    pa_sink *master;
    pa_sink_input_new_data sink_input_data;
    pa_sink_new_data sink_data;
    const char *plugin, *label, *input_ladspaport_map, *output_ladspaport_map;
    LADSPA_Descriptor_Function descriptor_func;
    unsigned long input_ladspaport[PA_CHANNELS_MAX], output_ladspaport[PA_CHANNELS_MAX];
    const char *e, *cdata;
    const LADSPA_Descriptor *d;
    unsigned long p, h, j, n_control, c;
    pa_bool_t *use_default = NULL;

    pa_assert(m);

    pa_assert_cc(sizeof(LADSPA_Data) == sizeof(float));

    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
        pa_log("Failed to parse module arguments.");
        goto fail;
    }

    if (!(master = pa_namereg_get(m->core, pa_modargs_get_value(ma, "master", NULL), PA_NAMEREG_SINK))) {
        pa_log("Master sink not found");
        goto fail;
    }

    ss = master->sample_spec;
    ss.format = PA_SAMPLE_FLOAT32;
    map = master->channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    if (!(plugin = pa_modargs_get_value(ma, "plugin", NULL))) {
        pa_log("Missing LADSPA plugin name");
        goto fail;
    }

    if (!(label = pa_modargs_get_value(ma, "label", NULL))) {
        pa_log("Missing LADSPA plugin label");
        goto fail;
    }

    if (!(input_ladspaport_map = pa_modargs_get_value(ma, "input_ladspaport_map", NULL)))
        pa_log_debug("Using default input ladspa port mapping");

    if (!(output_ladspaport_map = pa_modargs_get_value(ma, "output_ladspaport_map", NULL)))
        pa_log_debug("Using default output ladspa port mapping");

    cdata = pa_modargs_get_value(ma, "control", NULL);

    u = pa_xnew0(struct userdata, 1);
    u->module = m;
    m->userdata = u;
    u->memblockq = pa_memblockq_new(0, MEMBLOCKQ_MAXLENGTH, 0, pa_frame_size(&ss), 1, 1, 0, NULL);
    u->max_ladspaport_count = 1; /*to avoid division by zero etc. in pa__done when failing before this value has been set*/
    u->channels = 0;
    u->input = NULL;
    u->output = NULL;

    if (!(e = getenv("LADSPA_PATH")))
        e = LADSPA_PATH;

    /* FIXME: This is not exactly thread safe */
    t = pa_xstrdup(lt_dlgetsearchpath());
    lt_dlsetsearchpath(e);
    m->dl = lt_dlopenext(plugin);
    lt_dlsetsearchpath(t);
    pa_xfree(t);

    if (!m->dl) {
        pa_log("Failed to load LADSPA plugin: %s", lt_dlerror());
        goto fail;
    }

    if (!(descriptor_func = (LADSPA_Descriptor_Function) pa_load_sym(m->dl, NULL, "ladspa_descriptor"))) {
        pa_log("LADSPA module lacks ladspa_descriptor() symbol.");
        goto fail;
    }

    for (j = 0;; j++) {

        if (!(d = descriptor_func(j))) {
            pa_log("Failed to find plugin label '%s' in plugin '%s'.", label, plugin);
            goto fail;
        }

        if (strcmp(d->Label, label) == 0)
            break;
    }

    u->descriptor = d;

    pa_log_debug("Module: %s", plugin);
    pa_log_debug("Label: %s", d->Label);
    pa_log_debug("Unique ID: %lu", d->UniqueID);
    pa_log_debug("Name: %s", d->Name);
    pa_log_debug("Maker: %s", d->Maker);
    pa_log_debug("Copyright: %s", d->Copyright);

    n_control = 0;
    u->channels = ss.channels;

    /*
    * Enumerate ladspa ports
    * Default mapping is in order given by the plugin
    */
    for (p = 0; p < d->PortCount; p++) {
        if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p])) {
            if (LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
                pa_log_debug("Port %lu is input: %s", p, d->PortNames[p]);
                input_ladspaport[u->input_count] = p;
                u->input_count++;
            } else if (LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
                pa_log_debug("Port %lu is output: %s", p, d->PortNames[p]);
                output_ladspaport[u->output_count] = p;
                u->output_count++;
            }
        } else if (LADSPA_IS_PORT_CONTROL(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
            pa_log_debug("Port %lu is control: %s", p, d->PortNames[p]);
            n_control++;
        } else
            pa_log_debug("Ignored port %s", d->PortNames[p]);
        /* XXX: Has anyone ever seen an in-place plugin with non-equal number of input and output ports? */
        /* Could be if the plugin is for up-mixing stereo to 5.1 channels */
        /* Or if the plugin is down-mixing 5.1 to two channel stereo or binaural encoded signal */
        if (u->input_count > u->max_ladspaport_count)
            u->max_ladspaport_count = u->input_count;
        else
            u->max_ladspaport_count = u->output_count;
    }

    if (u->channels % u->max_ladspaport_count) {
        pa_log("Cannot handle non-integral number of plugins required for given number of channels");
        goto fail;
    }

    pa_log_debug("Will run %lu plugin instances", u->channels / u->max_ladspaport_count);

    /* Parse data for input ladspa port map */
    if (input_ladspaport_map) {
        const char *state = NULL;
        char *pname;
        c = 0;
        while ((pname = pa_split(input_ladspaport_map, ",", &state))) {
            if (c == u->input_count) {
                pa_log("Too many ports in input ladspa port map");
                goto fail;
            }


            for (p = 0; p < d->PortCount; p++) {
                if (strcmp(d->PortNames[p], pname) == 0) {
                    if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_INPUT(d->PortDescriptors[p])) {
                        input_ladspaport[c] = p;
                    } else {
                        pa_log("Port %s is not an audio input ladspa port", pname);
                        pa_xfree(pname);
                        goto fail;
                    }
                }
            }
            c++;
            pa_xfree(pname);
        }
    }

    /* Parse data for output port map */
    if (output_ladspaport_map) {
        const char *state = NULL;
        char *pname;
        c = 0;
        while ((pname = pa_split(output_ladspaport_map, ",", &state))) {
            if (c == u->output_count) {
                pa_log("Too many ports in output ladspa port map");
                goto fail;
            }
            for (p = 0; p < d->PortCount; p++) {
                if (strcmp(d->PortNames[p], pname) == 0) {
                    if (LADSPA_IS_PORT_AUDIO(d->PortDescriptors[p]) && LADSPA_IS_PORT_OUTPUT(d->PortDescriptors[p])) {
                        output_ladspaport[c] = p;
                    } else {
                        pa_log("Port %s is not an output ladspa port", pname);
                        pa_xfree(pname);
                        goto fail;
                    }
                }
            }
            c++;
            pa_xfree(pname);
        }
    }


    u->block_size = pa_frame_align(pa_mempool_block_size_max(m->core->mempool), &ss);

    /* Create buffers */
    if (LADSPA_IS_INPLACE_BROKEN(d->Properties)) {
        u->input = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->input_count);
        for (c = 0; c < u->input_count; c++)
            u->input[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
        u->output = (LADSPA_Data**) pa_xnew(LADSPA_Data*, (unsigned) u->output_count);
        for (c = 0; c < u->output_count; c++)
            u->output[c] = (LADSPA_Data*) pa_xnew(uint8_t, (unsigned) u->block_size);
    } else {
Beispiel #17
0
static int trigger(struct userdata *u, bool quick) {
    int enable_bits = 0, zero = 0;

    pa_assert(u);

    if (u->fd < 0)
        return 0;

    pa_log_debug("trigger");

    if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state))
        enable_bits |= PCM_ENABLE_INPUT;

    if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state))
        enable_bits |= PCM_ENABLE_OUTPUT;

    pa_log_debug("trigger: %i", enable_bits);

    if (u->use_mmap) {

        if (!quick)
            ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero);

#ifdef SNDCTL_DSP_HALT
        if (enable_bits == 0)
            if (ioctl(u->fd, SNDCTL_DSP_HALT, NULL) < 0)
                pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno));
#endif

        if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0)
            pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));

        if (u->sink && !(enable_bits & PCM_ENABLE_OUTPUT)) {
            pa_log_debug("clearing playback buffer");
            pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &u->sink->sample_spec);
        }

    } else {

        if (enable_bits)
            if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0)
                pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno));

        if (!quick) {
            /*
             * Some crappy drivers do not start the recording until we
             * read something.  Without this snippet, poll will never
             * register the fd as ready.
             */

            if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
                uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size);

                if (pa_read(u->fd, buf, u->in_fragment_size, NULL) < 0) {
                    pa_log("pa_read() failed: %s", pa_cstrerror(errno));
                    pa_xfree(buf);
                    return -1;
                }

                pa_xfree(buf);
            }
        }
    }

    return 0;
}
Beispiel #18
0
pa_bool_t pa_cpu_init_arm(pa_cpu_arm_flag_t *flags) {
#if defined (__arm__)
#if defined (__linux__)
    char *cpuinfo, *line;
    int arch;

    /* We need to read the CPU flags from /proc/cpuinfo because there is no user
     * space support to get the CPU features. This only works on linux AFAIK. */
    if (!(cpuinfo = get_cpuinfo())) {
        pa_log("Can't read cpuinfo");
        return;
    }

    *flags = 0;

    /* get the CPU architecture */
    if ((line = get_cpuinfo_line(cpuinfo, "CPU architecture"))) {
        arch = strtoul(line, NULL, 0);
        if (arch >= 6)
            *flags |= PA_CPU_ARM_V6;
        if (arch >= 7)
            *flags |= PA_CPU_ARM_V7;

        pa_xfree(line);
    }
    /* get the CPU features */
    if ((line = get_cpuinfo_line(cpuinfo, "Features"))) {
        const char *state = NULL;
        char *current;

        while ((current = pa_split_spaces(line, &state))) {
            if (!strcmp(current, "vfp"))
                *flags |= PA_CPU_ARM_VFP;
            else if (!strcmp(current, "edsp"))
                *flags |= PA_CPU_ARM_EDSP;
            else if (!strcmp(current, "neon"))
                *flags |= PA_CPU_ARM_NEON;
            else if (!strcmp(current, "vfpv3"))
                *flags |= PA_CPU_ARM_VFPV3;

            pa_xfree(current);
        }
    }
    pa_xfree(cpuinfo);

    pa_log_info("CPU flags: %s%s%s%s%s%s",
          (*flags & PA_CPU_ARM_V6) ? "V6 " : "",
          (*flags & PA_CPU_ARM_V7) ? "V7 " : "",
          (*flags & PA_CPU_ARM_VFP) ? "VFP " : "",
          (*flags & PA_CPU_ARM_EDSP) ? "EDSP " : "",
          (*flags & PA_CPU_ARM_NEON) ? "NEON " : "",
          (*flags & PA_CPU_ARM_VFPV3) ? "VFPV3 " : "");

    if (*flags & PA_CPU_ARM_V6)
        pa_volume_func_init_arm(*flags);

    return TRUE;

#else /* defined (__linux__) */
    pa_log ("ARM cpu features not yet supported on this OS");
#endif /* defined (__linux__) */

#else /* defined (__arm__) */
    return FALSE;
#endif /* defined (__arm__) */
}
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;
}
static void port_info_free(struct port_info *p_info) {
    pa_assert(p_info);

    pa_xfree(p_info->name);
    pa_xfree(p_info);
}
static void card_changed(struct userdata *u, struct udev_device *dev) {
    struct device *d;
    const char *path;
    const char *t;
    char *n;
    pa_strbuf *args_buf;

    pa_assert(u);
    pa_assert(dev);

    /* Maybe /dev/snd is now available? */
    setup_inotify(u);

    path = udev_device_get_devpath(dev);

    if ((d = pa_hashmap_get(u->devices, path))) {
        verify_access(u, d);
        return;
    }

    d = pa_xnew0(struct device, 1);
    d->path = pa_xstrdup(path);
    d->module = PA_INVALID_INDEX;
    PA_INIT_RATELIMIT(d->ratelimit, 10*PA_USEC_PER_SEC, 5);

    if (!(t = udev_device_get_property_value(dev, "PULSE_NAME")))
        if (!(t = udev_device_get_property_value(dev, "ID_ID")))
            if (!(t = udev_device_get_property_value(dev, "ID_PATH")))
                t = path_get_card_id(path);

    n = pa_namereg_make_valid_name(t);
    d->card_name = pa_sprintf_malloc("alsa_card.%s", n);
    args_buf = pa_strbuf_new();
    pa_strbuf_printf(args_buf,
                     "device_id=\"%s\" "
                     "name=\"%s\" "
                     "card_name=\"%s\" "
                     "namereg_fail=false "
                     "tsched=%s "
                     "fixed_latency_range=%s "
                     "ignore_dB=%s "
                     "deferred_volume=%s "
                     "use_ucm=%s "
                     "card_properties=\"module-udev-detect.discovered=1\"",
                     path_get_card_id(path),
                     n,
                     d->card_name,
                     pa_yes_no(u->use_tsched),
                     pa_yes_no(u->fixed_latency_range),
                     pa_yes_no(u->ignore_dB),
                     pa_yes_no(u->deferred_volume),
                     pa_yes_no(u->use_ucm));
    pa_xfree(n);

    if (u->tsched_buffer_size_valid)
        pa_strbuf_printf(args_buf, " tsched_buffer_size=%" PRIu32, u->tsched_buffer_size);

    d->args = pa_strbuf_tostring_free(args_buf);

    pa_hashmap_put(u->devices, d->path, d);

    verify_access(u, d);
}
Beispiel #22
0
char* sink_info_str(const pa_sink_info* i)
{
    static const char *state_table[] = {
        [1+PA_SINK_INVALID_STATE] = "n/a",
        [1+PA_SINK_RUNNING] = "RUNNING",
        [1+PA_SINK_IDLE] = "IDLE",
        [1+PA_SINK_SUSPENDED] = "SUSPENDED"
    };

    char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
    char cv[PA_CVOLUME_SNPRINT_MAX];
    char cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX];
    char v[PA_VOLUME_SNPRINT_MAX];
    char vdb[PA_SW_VOLUME_SNPRINT_DB_MAX];
    char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
    char* pl;

    char* str = g_strdup_printf(
            "Sink #%u\n"
            "State: %s\n"
            "Name: %s\n"
            "Description: %s\n"
            "Driver: %s\n"
            "Sample Specification: %s\n"
            "Channel Map: %s\n"
            "Owner Module: %u\n"
            "Mute: %s\n"
            "Volume: %s%s%s\n"
            "Balance: %0.2f\n"
            "Base Volume: %s%s%s%s\n"
            "Monitor Source: %s\n"
            "Latency: %0.0f usec, configured %0.0f usec\n"
            "Flags: %s%s%s%s%s%s%s\n"
            "Properties:\n\t\t%s",
            i->index,
            state_table[1+i->state],
            i->name,
            i->description,
            i->driver,
            pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
            i->owner_module,
            i->mute ? "yes" : "no",
            pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
            i->flags & PA_SINK_DECIBEL_VOLUME ? "\n        " : "",
            i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &i->volume) : "",
            pa_cvolume_get_balance(&i->volume, &i->channel_map),
            pa_volume_snprint(v, sizeof(v), i->base_volume),
            i->flags & PA_SINK_DECIBEL_VOLUME ? " (" : "",
            i->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), i->base_volume) : "",
            i->flags & PA_SINK_DECIBEL_VOLUME ? ")" : "",
            i->monitor_source_name,
            (double) i->latency, (double) i->configured_latency,
            i->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
            i->flags & PA_SINK_NETWORK ? "NETWORK " : "",
            i->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
            i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
            i->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
            i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
            i->flags & PA_SINK_SET_FORMATS ? "SET_FORMATS " : "",
            pl = pa_proplist_to_string_sep(i->proplist, "\n\t\t"));

    pa_xfree(pl);

    return str;
}
static void resolver_cb(
        AvahiServiceResolver *r,
        AvahiIfIndex interface, AvahiProtocol protocol,
        AvahiResolverEvent event,
        const char *name, const char *type, const char *domain,
        const char *host_name, const AvahiAddress *a, uint16_t port,
        AvahiStringList *txt,
        AvahiLookupResultFlags flags,
        void *userdata) {
    struct userdata *u = userdata;
    struct tunnel *tnl;
    char *device = NULL, *nicename, *dname, *vname, *args;
    char *tp = NULL, *et = NULL, *cn = NULL;
    char *ch = NULL, *ss = NULL, *sr = NULL;
    char *t = NULL;
    char at[AVAHI_ADDRESS_STR_MAX];
    AvahiStringList *l;
    pa_module *m;

    pa_assert(u);

    tnl = tunnel_new(interface, protocol, name, type, domain);

    if (event != AVAHI_RESOLVER_FOUND) {
        pa_log("Resolving of '%s' failed: %s", name, avahi_strerror(avahi_client_errno(u->client)));
        goto finish;
    }

    if ((nicename = strstr(name, "@"))) {
        ++nicename;
        if (strlen(nicename) > 0) {
            pa_log_debug("Found RAOP: %s", nicename);
            nicename = pa_escape(nicename, "\"'");
        } else
            nicename = NULL;
    }

    for (l = txt; l; l = l->next) {
        char *key, *value;
        pa_assert_se(avahi_string_list_get_pair(l, &key, &value, NULL) == 0);

        pa_log_debug("Found key: '%s' with value: '%s'", key, value);
        if (pa_streq(key, "device")) {
            device = value;
            value = NULL;
        } else if (pa_streq(key, "tp")) {
            /* Transport protocol:
             *  - TCP = only TCP,
             *  - UDP = only UDP,
             *  - TCP,UDP = both supported (UDP should be prefered) */
            pa_xfree(tp);
            if (pa_str_in_list(value, ",", "UDP"))
                tp = pa_xstrdup("UDP");
            else if (pa_str_in_list(value, ",", "TCP"))
                tp = pa_xstrdup("TCP");
            else
                tp = pa_xstrdup(value);
        } else if (pa_streq(key, "et")) {
            /* Supported encryption types:
             *  - 0 = none,
             *  - 1 = RSA,
             *  - 2 = FairPlay,
             *  - 3 = MFiSAP,
             *  - 4 = FairPlay SAPv2.5. */
            pa_xfree(et);
            if (pa_str_in_list(value, ",", "1"))
                et = pa_xstrdup("RSA");
            else
                et = pa_xstrdup("none");
        } else if (pa_streq(key, "cn")) {
            /* Suported audio codecs:
             *  - 0 = PCM,
             *  - 1 = ALAC,
             *  - 2 = AAC,
             *  - 3 = AAC ELD. */
            pa_xfree(cn);
            if (pa_str_in_list(value, ",", "1"))
                cn = pa_xstrdup("ALAC");
            else
                cn = pa_xstrdup("PCM");
        } else if (pa_streq(key, "md")) {
            /* Supported metadata types:
             *  - 0 = text,
             *  - 1 = artwork,
             *  - 2 = progress. */
        } else if (pa_streq(key, "pw")) {
            /* Requires password ? (true/false) */
        } else if (pa_streq(key, "ch")) {
            /* Number of channels */
            pa_xfree(ch);
            ch = pa_xstrdup(value);
        } else if (pa_streq(key, "ss")) {
            /* Sample size */
            pa_xfree(ss);
            ss = pa_xstrdup(value);
        } else if (pa_streq(key, "sr")) {
            /* Sample rate */
            pa_xfree(sr);
            sr = pa_xstrdup(value);
        }

        avahi_free(key);
        avahi_free(value);
    }

    if (device)
        dname = pa_sprintf_malloc("raop_output.%s.%s", host_name, device);
    else
        dname = pa_sprintf_malloc("raop_output.%s", host_name);

    if (!(vname = pa_namereg_make_valid_name(dname))) {
        pa_log("Cannot construct valid device name from '%s'.", dname);
        avahi_free(device);
        pa_xfree(dname);
        pa_xfree(tp);
        pa_xfree(et);
        pa_xfree(cn);
        pa_xfree(ch);
        pa_xfree(ss);
        pa_xfree(sr);
        goto finish;
    }

    avahi_free(device);
    pa_xfree(dname);

    avahi_address_snprint(at, sizeof(at), a);
    if (nicename) {
        args = pa_sprintf_malloc("server=[%s]:%u "
                                 "sink_name=%s "
                                 "sink_properties='device.description=\"%s (%s:%u)\"'",
                                 at, port,
                                 vname,
                                 nicename, at, port);
        pa_xfree(nicename);
    } else {
        args = pa_sprintf_malloc("server=[%s]:%u "
                                 "sink_name=%s"
                                 "sink_properties='device.description=\"%s:%u\"'",
                                 at, port,
                                 vname,
                                 at, port);
    }

    if (tp != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s protocol=%s", args, tp);
        pa_xfree(tp);
        pa_xfree(t);
    }
    if (et != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s encryption=%s", args, et);
        pa_xfree(et);
        pa_xfree(t);
    }
    if (cn != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s codec=%s", args, cn);
        pa_xfree(cn);
        pa_xfree(t);
    }
    if (ch != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s channels=%s", args, ch);
        pa_xfree(ch);
        pa_xfree(t);
    }
    if (ss != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s format=%s", args, ss);
        pa_xfree(ss);
        pa_xfree(t);
    }
    if (sr != NULL) {
        t = args;
        args = pa_sprintf_malloc("%s rate=%s", args, sr);
        pa_xfree(sr);
        pa_xfree(t);
    }

    pa_log_debug("Loading module-raop-sink with arguments '%s'", args);

    if ((m = pa_module_load(u->core, "module-raop-sink", args))) {
        tnl->module_index = m->index;
        pa_hashmap_put(u->tunnels, tnl, tnl);
        tnl = NULL;
    }

    pa_xfree(vname);
    pa_xfree(args);

finish:
    avahi_service_resolver_free(r);

    if (tnl)
        tunnel_free(tnl);
}
Beispiel #24
0
int ao_plugin_open(ao_device *device, ao_sample_format *format) {
    char *p=NULL, t[256], t2[256];
    const char *fn = NULL;
    ao_pulse_internal *internal;
    struct pa_sample_spec ss;
    struct pa_channel_map map;
    struct pa_buffer_attr battr;
    size_t allocated = 128;

    assert(device && device->internal && format);

    internal = (ao_pulse_internal *) device->internal;

    if (format->bits == 8)
      ss.format = PA_SAMPLE_U8;
    else if (format->bits == 16)
      ss.format = PA_SAMPLE_S16NE;
#ifdef PA_SAMPLE_S24NE
    else if (format->bits == 24)
      ss.format = PA_SAMPLE_S24NE;
#endif
    else
        return 0;

    if (device->output_channels <= 0 || device->output_channels > PA_CHANNELS_MAX)
      return 0;

    ss.channels = device->output_channels;
    ss.rate = format->rate;

    disable_sigpipe();

    if (internal->client_name) {
        snprintf(t, sizeof(t), "libao[%s]", internal->client_name);
        snprintf(t2, sizeof(t2), "libao[%s] playback stream", internal->client_name);
    } else {
      while (1) {
        p = pa_xmalloc(allocated);

        if (!(fn = pa_get_binary_name(p, allocated))) {
          break;
        }

        if (fn != p || strlen(p) < allocated - 1) {
          fn = pa_path_get_filename(fn);
          snprintf(t, sizeof(t), "libao[%s]", fn);
          snprintf(t2, sizeof(t2), "libao[%s] playback stream", fn);
          break;
        }

        pa_xfree(p);
        allocated *= 2;
      }
      pa_xfree(p);
      p = NULL;
      if (!fn) {
        strcpy(t, "libao");
        strcpy(t2, "libao playback stream");
      }
    }

    if(device->input_map){
      int i;
      pa_channel_map_init(&map);
      map.channels=device->output_channels;

      for(i=0;i<device->output_channels;i++){
        if(device->input_map[i]==-1){
          map.map[i] = PA_CHANNEL_POSITION_INVALID;
        }else{
          map.map[i] = device->input_map[i];
        }
      }
    }

    /* buffering attributes */
    battr.prebuf = battr.minreq = battr.fragsize = -1;

    battr.tlength = (int)(internal->buffer_time * format->rate) / 1000000 *
      ((format->bits+7)/8) + device->output_channels;
    battr.minreq = battr.tlength/4;
    battr.maxlength = battr.tlength+battr.minreq;

    internal->simple = pa_simple_new(internal->server, t, PA_STREAM_PLAYBACK,
                                     internal->sink, t2, &ss,
                                     (device->input_map ? &map : NULL), &battr, NULL);
    if (!internal->simple)
        return 0;

    device->driver_byte_format = AO_FMT_NATIVE;

    internal->static_delay = pa_simple_get_latency(internal->simple, NULL);
    if(internal->static_delay<0) internal->static_delay = 0;

    return 1;
}
int pa__init(pa_module *m) {
    struct userdata *u = NULL;
    pa_modargs *ma = NULL;
    pa_sink_new_data sink_data;
    pa_sample_spec ss;
    pa_channel_map map;
    const char *remote_server = NULL;
    const char *sink_name = NULL;
    const char *compression = NULL;
    char *default_sink_name = NULL;

    pa_assert(m);

    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
        pa_log("Failed to parse module arguments.");
        goto fail;
    }

    ss = m->core->default_sample_spec;
    map = m->core->default_channel_map;
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
        pa_log("Invalid sample format specification or channel map");
        goto fail;
    }

    remote_server = pa_modargs_get_value(ma, "server", NULL);
    if (!remote_server) {
        pa_log("No server given!");
        goto fail;
    }

    u = pa_xnew0(struct userdata, 1);
    u->module = m;
    m->userdata = u;
    u->remote_server = pa_xstrdup(remote_server);
    u->thread_mainloop = pa_mainloop_new();
    if (u->thread_mainloop == NULL) {
        pa_log("Failed to create mainloop");
        goto fail;
    }
    u->thread_mainloop_api = pa_mainloop_get_api(u->thread_mainloop);
    u->cookie_file = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL));
    u->remote_sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));

    u->thread_mq = pa_xnew0(pa_thread_mq, 1);
    pa_thread_mq_init_thread_mainloop(u->thread_mq, m->core->mainloop, u->thread_mainloop_api);

    /* Create sink */
    pa_sink_new_data_init(&sink_data);
    sink_data.driver = __FILE__;
    sink_data.module = m;

    default_sink_name = pa_sprintf_malloc("tunnel-sink-new.%s", remote_server);
    sink_name = pa_modargs_get_value(ma, "sink_name", default_sink_name);

    compression = pa_modargs_get_value(ma, "compression", NULL);
    if (compression) {
        pa_log("compression activated");
        memset(&u->transcode, 0, sizeof(pa_transcode));

        if(strcmp(compression, "opus") == 0 && pa_transcode_supported(PA_ENCODING_OPUS)){

             compression = pa_modargs_get_value(ma, "compression-frame_size", NULL);
             if(compression) u->transcode.frame_size = atoi(compression);
             compression = pa_modargs_get_value(ma, "compression-bitrate", NULL);
             if(compression) u->transcode.bitrate = atoi(compression);

             pa_transcode_init(&u->transcode, PA_ENCODING_OPUS, PA_TRANSCODE_ENCODER, NULL, &ss);

         }
    }
    else u->transcode.encoding = -1;
        
    pa_sink_new_data_set_name(&sink_data, sink_name);
    pa_sink_new_data_set_sample_spec(&sink_data, &ss);
    pa_sink_new_data_set_channel_map(&sink_data, &map);

    pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_CLASS, "sound");
    pa_proplist_setf(sink_data.proplist,
                     PA_PROP_DEVICE_DESCRIPTION,
                     _("Tunnel to %s/%s"),
                     remote_server,
                     pa_strempty(u->remote_sink_name));

    if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
        pa_log("Invalid properties");
        pa_sink_new_data_done(&sink_data);
        goto fail;
    }
    if (!(u->sink = pa_sink_new(m->core, &sink_data, PA_SINK_LATENCY | PA_SINK_DYNAMIC_LATENCY | PA_SINK_NETWORK))) {
        pa_log("Failed to create sink.");
        pa_sink_new_data_done(&sink_data);
        goto fail;
    }

    pa_sink_new_data_done(&sink_data);
    u->sink->userdata = u;
    u->sink->parent.process_msg = sink_process_msg_cb;
    u->sink->update_requested_latency = sink_update_requested_latency_cb;
    pa_sink_set_latency_range(u->sink, 0, MAX_LATENCY_USEC);

    /* set thread message queue */
    pa_sink_set_asyncmsgq(u->sink, u->thread_mq->inq);

    if (!(u->thread = pa_thread_new("tunnel-sink", thread_func, u))) {
        pa_log("Failed to create thread.");
        goto fail;
    }

    pa_sink_put(u->sink);
    pa_modargs_free(ma);
    pa_xfree(default_sink_name);

    return 0;

fail:
    if (ma)
        pa_modargs_free(ma);

    if (default_sink_name)
        pa_xfree(default_sink_name);

    pa__done(m);

    return -1;
}
Beispiel #26
0
int ao_plugin_test(void) {
    char *p=NULL, t[256], t2[256];
    const char *fn;
    struct pa_simple *s;
    static const struct pa_sample_spec ss = {
        .format = PA_SAMPLE_S16NE,
        .rate = 44100,
        .channels = 2
    };
    size_t allocated = 128;

    disable_sigpipe();

    if (getenv("PULSE_SERVER") || getenv("PULSE_SINK"))
        return 1;

    while (1) {
      p = pa_xmalloc(allocated);

      if (!(fn = pa_get_binary_name(p, allocated))) {
        break;
      }

      if (fn != p || strlen(p) < allocated - 1) {
        snprintf(t, sizeof(t), "libao[%s]", fn);
        snprintf(t2, sizeof(t2), "libao[%s] test", fn);
        break;
      }

      pa_xfree(p);
      allocated *= 2;
    }
    pa_xfree(p);
    p = NULL;

    if (!(s = pa_simple_new(NULL, fn ? t : "libao", PA_STREAM_PLAYBACK, NULL, fn ? t2 : "libao test", &ss, NULL, NULL, NULL)))
        return 0;

    pa_simple_free(s);
    return 1;
}

ao_info *ao_plugin_driver_info(void) {
    return &ao_pulse_info;
}

int ao_plugin_device_init(ao_device *device) {
    ao_pulse_internal *internal;
    assert(device);

    internal = (ao_pulse_internal *) malloc(sizeof(ao_pulse_internal));

    if (internal == NULL)
        return 0;

    internal->simple = NULL;
    internal->server = NULL;
    internal->sink = NULL;
    internal->client_name = NULL;
    internal->buffer_time = AO_PULSE_BUFFER_TIME;

    device->internal = internal;
    device->output_matrix_order = AO_OUTPUT_MATRIX_PERMUTABLE;
    device->output_matrix = strdup("M,L,R,C,BC,BL,BR,LFE,CL,CR,SL,SR,"
                                   "A0,A1,A2,A3,A4,A5,A6,A7,A8,A9,"
                                   "A10,A11,A12,A13,A14,A15,A16,A17,A18,A19,"
                                   "A20,A21,A22,A23,A24,A25,A26,A27,A28,A29,"
                                   "A30,A31");
    return 1;
}
Beispiel #27
0
/* Create a new PID file for the current process. */
int pa_pid_file_create(const char *procname) {
    int fd = -1;
    int ret = -1;
    char t[20];
    pid_t pid;
    size_t l;
    char *fn;

#ifdef OS_IS_WIN32
    HANDLE process;
#endif

    if (!(fn = pa_runtime_path("pid")))
        goto fail;

    if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0)
        goto fail;

    if ((pid = read_pid(fn, fd)) == (pid_t) -1)
        pa_log_warn("Corrupt PID file, overwriting.");
    else if (pid > 0) {
        int ours = 1;

#ifdef OS_IS_WIN32
        if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
            CloseHandle(process);
#else
        if (kill(pid, 0) >= 0 || errno != ESRCH) {
#endif

            if (procname)
                if ((ours = proc_name_ours(pid, procname)) < 0) {
                    pa_log_warn("Could not check to see if pid %lu is a pulseaudio process. "
                                "Assuming it is and the daemon is already running.", (unsigned long) pid);
                    goto fail;
                }

            if (ours) {
                pa_log("Daemon already running.");
                ret = 1;
                goto fail;
            }
        }

        pa_log_warn("Stale PID file, overwriting.");
    }

    /* Overwrite the current PID file */
    if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, (off_t) 0) < 0) {
        pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
        goto fail;
    }

    pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
    l = strlen(t);

    if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) {
        pa_log("Failed to write PID file.");
        goto fail;
    }

    ret = 0;

fail:
    if (fd >= 0) {
        pa_lock_fd(fd, 0);

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

    pa_xfree(fn);

    return ret;
}

/* Remove the PID file, if it is ours */
int pa_pid_file_remove(void) {
    int fd = -1;
    char *fn;
    int ret = -1;
    pid_t pid;

    if (!(fn = pa_runtime_path("pid")))
        goto fail;

    if ((fd = open_pid_file(fn, O_RDWR)) < 0) {
        pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
        goto fail;
    }

    if ((pid = read_pid(fn, fd)) == (pid_t) -1)
        goto fail;

    if (pid != getpid()) {
        pa_log("PID file '%s' not mine!", fn);
        goto fail;
    }

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

#ifdef OS_IS_WIN32
    pa_lock_fd(fd, 0);
    pa_close(fd);
    fd = -1;
#endif

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

    ret = 0;

fail:

    if (fd >= 0) {
        pa_lock_fd(fd, 0);

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

    pa_xfree(fn);

    return ret;
}
Beispiel #28
0
int pa_context_connect(
        pa_context *c,
        const char *server,
        pa_context_flags_t flags,
        const pa_spawn_api *api) {

    int r = -1;

    pa_assert(c);
    pa_assert(PA_REFCNT_VALUE(c) >= 1);

    PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED);
    PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE);
    PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID);
    PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID);

    if (server)
        c->conf->autospawn = FALSE;
    else
        server = c->conf->default_server;

    pa_context_ref(c);

    c->no_fail = !!(flags & PA_CONTEXT_NOFAIL);
    c->server_specified = !!server;
    pa_assert(!c->server_list);

    if (server) {
        if (!(c->server_list = pa_strlist_parse(server))) {
            pa_context_fail(c, PA_ERR_INVALIDSERVER);
            goto finish;
        }

    } else {
        char *d;

        /* Prepend in reverse order */

        /* Follow the X display */
        if (c->conf->auto_connect_display) {
            if ((d = getenv("DISPLAY"))) {
                d = pa_xstrndup(d, strcspn(d, ":"));

                if (*d)
                    c->server_list = pa_strlist_prepend(c->server_list, d);

                pa_xfree(d);
            }
        }

        /* Add TCP/IP on the localhost */
        if (c->conf->auto_connect_localhost) {
            c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]");
            c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1");
        }

        /* The system wide instance via PF_LOCAL */
        c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);

        /* The user instance via PF_LOCAL */
        c->server_list = prepend_per_user(c->server_list);
    }

    /* Set up autospawning */
    if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {

#ifdef HAVE_GETUID
        if (getuid() == 0)
            pa_log_debug("Not doing autospawn since we are root.");
        else {
            c->do_autospawn = TRUE;

            if (api)
                c->spawn_api = *api;
        }
#endif
    }

    pa_context_set_state(c, PA_CONTEXT_CONNECTING);
    r = try_next_connection(c);

finish:
    pa_context_unref(c);

    return r;
}
Beispiel #29
0
static int try_next_connection(pa_context *c) {
    char *u = NULL;
    int r = -1;

    pa_assert(c);
    pa_assert(!c->client);

    for (;;) {
        pa_xfree(u);
        u = NULL;

        c->server_list = pa_strlist_pop(c->server_list, &u);

        if (!u) {

#ifndef OS_IS_WIN32
            if (c->do_autospawn) {

                if ((r = context_autospawn(c)) < 0)
                    goto finish;

                /* Autospawn only once */
                c->do_autospawn = false;

                /* Connect only to per-user sockets this time */
                c->server_list = prepend_per_user(c->server_list);

                /* Retry connection */
                continue;
            }
#endif

#ifdef HAVE_DBUS
            if (c->no_fail && !c->server_specified) {
                if (!c->session_bus)
                    track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_bus);
                if (!c->system_bus)
                    track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus);

                if (c->session_bus || c->system_bus) {
                    pa_log_debug("Waiting for PA on D-Bus...");
                    break;
                }
            } else
#endif
                pa_context_fail(c, PA_ERR_CONNECTIONREFUSED);

            goto finish;
        }

        pa_log_debug("Trying to connect to %s...", u);

        pa_xfree(c->server);
        c->server = pa_xstrdup(u);

        if (!(c->client = pa_socket_client_new_string(c->mainloop, c->use_rtclock, u, PA_NATIVE_DEFAULT_PORT)))
            continue;

        c->is_local = pa_socket_client_is_local(c->client);
        pa_socket_client_set_callback(c->client, on_connection, c);
        break;
    }

    r = 0;

finish:
    pa_xfree(u);

    return r;
}
Beispiel #30
0
void pa_format_info_free(pa_format_info *f) {
    pa_assert(f);

    pa_proplist_free(f->plist);
    pa_xfree(f);
}