Exemplo n.º 1
0
pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata) {
    pa_operation *o;
    pa_tagstruct *t;
    uint32_t tag;

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

    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
    PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);

    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);

    t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
    pa_tagstruct_putu32(t, (uint32_t) mode);
    pa_tagstruct_put_proplist(t, p);

    pa_pstream_send_tagstruct(c->pstream, t);
    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);

    /* Please note that we don't update c->proplist here, because we
     * don't export that field */

    return o;
}
Exemplo n.º 2
0
pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_proplist *p, pa_context_play_sample_cb_t cb, void *userdata) {
    pa_operation *o;
    pa_tagstruct *t;
    uint32_t tag;

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

    PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED);
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
    PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
    PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID);
    PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);

    o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);

    if (!dev)
        dev = c->conf->default_sink;

    t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag);
    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
    pa_tagstruct_puts(t, dev);

    if (!PA_VOLUME_IS_VALID(volume) && c->version < 15)
        volume = PA_VOLUME_NORM;

    pa_tagstruct_putu32(t, volume);
    pa_tagstruct_puts(t, name);

    if (p)
        pa_tagstruct_put_proplist(t, p);
    else {
        p = pa_proplist_new();
        pa_tagstruct_put_proplist(t, p);
        pa_proplist_free(p);
    }

    pa_pstream_send_tagstruct(c->pstream, t);
    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, play_sample_with_proplist_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);

    return o;
}
Exemplo n.º 3
0
int pa_stream_connect_upload(pa_stream *s, size_t length) {
    pa_tagstruct *t;
    uint32_t tag;
    const char *name;

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

    PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED);
    PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE);
    PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID);
    PA_CHECK_VALIDITY(s->context, length == (size_t) (uint32_t) length, PA_ERR_INVALID);
    PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);

    if (!(name = pa_proplist_gets(s->proplist, PA_PROP_EVENT_ID)))
        name = pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME);

    PA_CHECK_VALIDITY(s->context, name && *name && pa_utf8_valid(name), PA_ERR_INVALID);

    pa_stream_ref(s);

    s->direction = PA_STREAM_UPLOAD;
    s->flags = 0;

    t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag);

    pa_tagstruct_puts(t, name);
    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
    pa_tagstruct_put_channel_map(t, &s->channel_map);
    pa_tagstruct_putu32(t, (uint32_t) length);

    if (s->context->version >= 13)
        pa_tagstruct_put_proplist(t, s->proplist);

    pa_pstream_send_tagstruct(s->context->pstream, t);
    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL);

    pa_stream_set_state(s, PA_STREAM_CREATING);

    pa_stream_unref(s);
    return 0;
}
Exemplo n.º 4
0
static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
    pa_context *c = userdata;

    pa_assert(pd);
    pa_assert(c);
    pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);

    pa_context_ref(c);

    if (command != PA_COMMAND_REPLY) {
        pa_context_handle_error(c, command, t, TRUE);
        goto finish;
    }

    switch(c->state) {
        case PA_CONTEXT_AUTHORIZING: {
            pa_tagstruct *reply;
            pa_bool_t shm_on_remote = FALSE;

            if (pa_tagstruct_getu32(t, &c->version) < 0 ||
                !pa_tagstruct_eof(t)) {
                pa_context_fail(c, PA_ERR_PROTOCOL);
                goto finish;
            }

            /* Minimum supported version */
            if (c->version < 8) {
                pa_context_fail(c, PA_ERR_VERSION);
                goto finish;
            }

            /* Starting with protocol version 13 the MSB of the version
               tag reflects if shm is available for this connection or
               not. */
            if (c->version >= 13) {
                shm_on_remote = !!(c->version & 0x80000000U);
                c->version &= 0x7FFFFFFFU;
            }

            pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);

            /* Enable shared memory support if possible */
            if (c->do_shm)
                if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
                    c->do_shm = FALSE;

            if (c->do_shm) {

                /* Only enable SHM if both sides are owned by the same
                 * user. This is a security measure because otherwise
                 * data private to the user might leak. */

#ifdef HAVE_CREDS
                const pa_creds *creds;
                if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
                    c->do_shm = FALSE;
#endif
            }

            pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm));
            pa_pstream_enable_shm(c->pstream, c->do_shm);

            reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);

            if (c->version >= 13) {
                pa_init_proplist(c->proplist);
                pa_tagstruct_put_proplist(reply, c->proplist);
            } else
                pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME));

            pa_pstream_send_tagstruct(c->pstream, reply);
            pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);

            pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
            break;
        }

        case PA_CONTEXT_SETTING_NAME :

            if ((c->version >= 13 && (pa_tagstruct_getu32(t, &c->client_index) < 0 ||
                                      c->client_index == PA_INVALID_INDEX)) ||
                !pa_tagstruct_eof(t)) {
                pa_context_fail(c, PA_ERR_PROTOCOL);
                goto finish;
            }

            pa_context_set_state(c, PA_CONTEXT_READY);
            break;

        default:
            pa_assert_not_reached();
    }

finish:
    pa_context_unref(c);
}
Exemplo n.º 5
0
static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
    pa_context *c = userdata;

    pa_assert(pd);
    pa_assert(c);
    pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME);

    pa_context_ref(c);

    if (command != PA_COMMAND_REPLY) {
        pa_context_handle_error(c, command, t, true);
        goto finish;
    }

    switch(c->state) {
        case PA_CONTEXT_AUTHORIZING: {
            pa_tagstruct *reply;
            bool shm_on_remote = false;
            bool memfd_on_remote = false;

            if (pa_tagstruct_getu32(t, &c->version) < 0 ||
                !pa_tagstruct_eof(t)) {
                pa_context_fail(c, PA_ERR_PROTOCOL);
                goto finish;
            }

            /* Minimum supported version */
            if (c->version < 8) {
                pa_context_fail(c, PA_ERR_VERSION);
                goto finish;
            }

            /* Starting with protocol version 13 the MSB of the version
               tag reflects if shm is available for this connection or
               not. */
            if (c->version >= 13) {
                shm_on_remote = !!(c->version & 0x80000000U);

                /* Starting with protocol version 31, the second MSB of the version
                 * tag reflects whether memfd is supported on the other PA end. */
                if (c->version >= 31)
                    memfd_on_remote = !!(c->version & 0x40000000U);

                /* Reserve the two most-significant _bytes_ of the version tag
                 * for flags. */
                c->version &= 0x0000FFFFU;
            }

            pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION);

            /* Enable shared memory support if possible */
            if (c->do_shm)
                if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
                    c->do_shm = false;

            if (c->do_shm) {

                /* Only enable SHM if both sides are owned by the same
                 * user. This is a security measure because otherwise
                 * data private to the user might leak. */

#ifdef HAVE_CREDS
                const pa_creds *creds;
                if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
                    c->do_shm = false;
#endif
            }

            pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm));
            pa_pstream_enable_shm(c->pstream, c->do_shm);

            c->shm_type = PA_MEM_TYPE_PRIVATE;
            if (c->do_shm) {
                if (c->version >= 31 && memfd_on_remote && c->memfd_on_local) {
                    const char *reason;

                    pa_pstream_enable_memfd(c->pstream);
                    if (pa_mempool_is_memfd_backed(c->mempool))
                        if (pa_pstream_register_memfd_mempool(c->pstream, c->mempool, &reason))
                            pa_log("Failed to regester memfd mempool. Reason: %s", reason);

                    /* Even if memfd pool registration fails, the negotiated SHM type
                     * shall remain memfd as both endpoints claim to support it. */
                    c->shm_type = PA_MEM_TYPE_SHARED_MEMFD;
                } else
                    c->shm_type = PA_MEM_TYPE_SHARED_POSIX;
            }

            pa_log_debug("Memfd possible: %s", pa_yes_no(c->memfd_on_local));
            pa_log_debug("Negotiated SHM type: %s", pa_mem_type_to_string(c->shm_type));

            reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);

            if (c->version >= 13) {
                pa_init_proplist(c->proplist);
                pa_tagstruct_put_proplist(reply, c->proplist);
            } else
                pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME));

            pa_pstream_send_tagstruct(c->pstream, reply);
            pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);

            pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
            break;
        }

        case PA_CONTEXT_SETTING_NAME :

            if ((c->version >= 13 && (pa_tagstruct_getu32(t, &c->client_index) < 0 ||
                                      c->client_index == PA_INVALID_INDEX)) ||
                !pa_tagstruct_eof(t)) {
                pa_context_fail(c, PA_ERR_PROTOCOL);
                goto finish;
            }

            pa_context_set_state(c, PA_CONTEXT_READY);
            break;

        default:
            pa_assert_not_reached();
    }

finish:
    pa_context_unref(c);
}
Exemplo n.º 6
0
void on_set_common(pa_proplist* p, pa_tagstruct* t, pa_core* c)
{
    pa_log_info("on_set_common");

    const char* attribute = pa_proplist_gets(p, PROPLIST_KEY_ATTRIBUTE);
    if (!attribute) {
        pa_log_error("on_set_common: attribute not found!");
        return;
    }

    if (!strcmp(attribute, PROPLIST_VALUE_GET_INFO)) {
        const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE);
        if (!str_device) {
            pa_log_error("on_set_common device not specific!");
            return;
        }

        int device_id = atoi(str_device);
        pa_sink* sink = NULL;
        pa_source* source = NULL;

        sink = find_sink(c, device_id);
        if (!sink) {
            source = find_source(c, device_id);
        }

        if (!sink && !source) {
            pa_log_error("do not find any sink or source of device %d", device_id);
            return;
        }

        int n_used = 0;
        if (sink) {
            n_used = pa_module_get_n_used(sink->module);
        }
        else {
            n_used = pa_module_get_n_used(source->module);
        }

        char value[32];
        snprintf(value, sizeof(value), "%d", n_used);
        pa_proplist* replyp = pa_proplist_new();
        pa_proplist_sets(replyp, PROPLIST_KEY_VALUE, value);
        pa_tagstruct_put_proplist(t, replyp);
        pa_proplist_free(replyp);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_REMOTE_SINK)) {
#ifdef HAVE_WEB_SOCKET
        extern void start_web_socket();
        start_web_socket();
#endif
        on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_REMOTE, NULL);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_FILE_SINK)) {
        const char* str_path = pa_proplist_gets(p, PROPLIST_VALUE_PATH);
        char args[64] = { 0 };
        if (str_path) {
            snprintf(args, sizeof(args), "path=%s", str_path);
        }
        on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_FILE, str_path ? args : NULL);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_ALSA_BUFFER)) {
        const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE);
        if (!str_device) {
            pa_log_error("on_set_common alsa-buffer device not specific!");
            return;
        }

        int device = atoi(str_device);
        pa_sink* s = find_sink(c, device);
        if (!s) {
            pa_log_error("sink not found %d", device);
            return;
        }

        pa_usec_t left_to_play = pa_sink_get_left_to_play(s);
        pa_proplist* replyp = pa_proplist_new();
        pa_proplist_set(replyp, PROPLIST_KEY_COMMAND_RESULT, &left_to_play, sizeof(left_to_play));
        pa_tagstruct_put_proplist(t, replyp);
        pa_proplist_free(replyp);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_STOP_TEST)) {
        pthread_t tid_stop;
        int err = pthread_create(&tid_stop, NULL, stop_thread, NULL);
        if (err != 0) {
            pa_log_error("can't create thread: %s\n", strerror(err));
            return;
        }
    }
#ifdef HAVE_WEB_SOCKET
        else if (!strcmp(attribute, "web-start")) {
            extern void start_web_socket();
            start_web_socket();
        }
        else if (!strcmp(attribute, "web-stop")) {
            extern void stop_web_socket();
            stop_web_socket();
        }
#endif
}